From f2dcba32002877a69466ad4f6b80948534dfe4cd Mon Sep 17 00:00:00 2001 From: Ruben Perez Date: Wed, 5 Oct 2022 20:43:11 +0200 Subject: [PATCH] deserialize_text_field tests --- ...ation.hpp => deserialize_binary_field.hpp} | 13 +- .../mysql/detail/protocol/deserialize_row.hpp | 57 +--- ...ization.hpp => deserialize_text_field.hpp} | 15 +- ...ation.ipp => deserialize_binary_field.ipp} | 56 +-- .../detail/protocol/impl/deserialize_row.ipp | 177 ++++++++++ ...ization.ipp => deserialize_text_field.ipp} | 49 +-- include/boost/mysql/field_view.hpp | 5 + include/boost/mysql/impl/field_view.hpp | 13 +- test/CMakeLists.txt | 8 +- ...n_value.cpp => deserialize_text_field.cpp} | 320 +++++++++++++++++- .../prepared_statement_messages.hpp | 23 +- .../protocol/text_deserialization_error.cpp | 271 --------------- 12 files changed, 541 insertions(+), 466 deletions(-) rename include/boost/mysql/detail/protocol/{binary_deserialization.hpp => deserialize_binary_field.hpp} (66%) rename include/boost/mysql/detail/protocol/{text_deserialization.hpp => deserialize_text_field.hpp} (61%) rename include/boost/mysql/detail/protocol/impl/{binary_deserialization.ipp => deserialize_binary_field.ipp} (84%) create mode 100644 include/boost/mysql/detail/protocol/impl/deserialize_row.ipp rename include/boost/mysql/detail/protocol/impl/{text_deserialization.ipp => deserialize_text_field.ipp} (87%) rename test/unit/detail/protocol/{text_deserialization_value.cpp => deserialize_text_field.cpp} (56%) delete mode 100644 test/unit/detail/protocol/text_deserialization_error.cpp diff --git a/include/boost/mysql/detail/protocol/binary_deserialization.hpp b/include/boost/mysql/detail/protocol/deserialize_binary_field.hpp similarity index 66% rename from include/boost/mysql/detail/protocol/binary_deserialization.hpp rename to include/boost/mysql/detail/protocol/deserialize_binary_field.hpp index 743a8da2..2b891515 100644 --- a/include/boost/mysql/detail/protocol/binary_deserialization.hpp +++ b/include/boost/mysql/detail/protocol/deserialize_binary_field.hpp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP -#define BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP +#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP +#define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP #include #include @@ -26,17 +26,10 @@ inline errc deserialize_binary_field( field_view& output ); -inline error_code deserialize_binary_row( - deserialization_context& ctx, - const std::vector& meta, - const std::uint8_t* buffer_first, - std::vector& output -); - } // detail } // mysql } // boost -#include +#include #endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP_ */ diff --git a/include/boost/mysql/detail/protocol/deserialize_row.hpp b/include/boost/mysql/detail/protocol/deserialize_row.hpp index 4998a502..0ea16fed 100644 --- a/include/boost/mysql/detail/protocol/deserialize_row.hpp +++ b/include/boost/mysql/detail/protocol/deserialize_row.hpp @@ -8,11 +8,10 @@ #ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_ROW_HPP #define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_ROW_HPP +#include #include #include -#include -#include -#include +#include #include #include #include @@ -23,6 +22,16 @@ namespace boost { namespace mysql { namespace detail { +// Exposed here for the sake of testing +inline void deserialize_row( + resultset_encoding encoding, + deserialization_context& ctx, + const std::vector& meta, + const std::uint8_t* buffer_first, + std::vector& output, + error_code& err +); + inline bool deserialize_row( boost::asio::const_buffer read_message, @@ -32,45 +41,7 @@ inline bool deserialize_row( std::vector& output, error_code& err, error_info& info -) -{ - assert(result.valid()); - - // Message type: row, error or eof? - std::uint8_t msg_type = 0; - deserialization_context ctx (read_message, current_capabilities); - err = make_error_code(deserialize(ctx, msg_type)); - if (err) - return false; - if (msg_type == eof_packet_header) - { - // end of resultset => this is a ok_packet, not a row - ok_packet ok_pack; - err = deserialize_message(ctx, ok_pack); - if (err) - return false; - result.complete(ok_pack); - output.clear(); - return false; - } - else if (msg_type == error_packet_header) - { - // An error occurred during the generation of the rows - err = process_error_packet(ctx, info); - return false; - } - else - { - // An actual row - ctx.rewind(1); // keep the 'message type' byte, as it is part of the actual message - err = result.encoding() == detail::resultset_encoding::text ? - deserialize_text_row(ctx, result.meta(), buffer_first, output) : - deserialize_binary_row(ctx, result.meta(), buffer_first, output); - if (err) - return false; - return true; - } -} +); inline void offsets_to_string_views( std::vector& fields, @@ -86,5 +57,7 @@ inline void offsets_to_string_views( } // mysql } // boost +#include + #endif diff --git a/include/boost/mysql/detail/protocol/text_deserialization.hpp b/include/boost/mysql/detail/protocol/deserialize_text_field.hpp similarity index 61% rename from include/boost/mysql/detail/protocol/text_deserialization.hpp rename to include/boost/mysql/detail/protocol/deserialize_text_field.hpp index 98c01260..6907134b 100644 --- a/include/boost/mysql/detail/protocol/text_deserialization.hpp +++ b/include/boost/mysql/detail/protocol/deserialize_text_field.hpp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_TEXT_DESERIALIZATION_HPP -#define BOOST_MYSQL_DETAIL_PROTOCOL_TEXT_DESERIALIZATION_HPP +#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP +#define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP #include #include @@ -19,24 +19,17 @@ namespace boost { namespace mysql { namespace detail { -inline errc deserialize_text_value( +inline errc deserialize_text_field( boost::string_view from, const metadata& meta, const std::uint8_t* buffer_first, field_view& output ); -inline error_code deserialize_text_row( - deserialization_context& ctx, - const std::vector& meta, - const std::uint8_t* buffer_first, - std::vector& output -); - } // detail } // mysql } // boost -#include +#include #endif diff --git a/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp b/include/boost/mysql/detail/protocol/impl/deserialize_binary_field.ipp similarity index 84% rename from include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp rename to include/boost/mysql/detail/protocol/impl/deserialize_binary_field.ipp index ca447d86..85e30fa7 100644 --- a/include/boost/mysql/detail/protocol/impl/binary_deserialization.ipp +++ b/include/boost/mysql/detail/protocol/impl/deserialize_binary_field.ipp @@ -5,15 +5,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP -#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP +#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_BINARY_FIELD_IPP +#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_BINARY_FIELD_IPP #pragma once #include -#include +#include #include -#include #include #include #include @@ -369,53 +368,4 @@ inline boost::mysql::errc boost::mysql::detail::deserialize_binary_field( } } -inline boost::mysql::error_code boost::mysql::detail::deserialize_binary_row( - deserialization_context& ctx, - const std::vector& meta, - const std::uint8_t* buffer_first, - std::vector& output -) -{ - std::size_t old_size = output.size(); - - // Skip packet header (it is not part of the message in the binary - // protocol but it is in the text protocol, so we include it for homogeneity) - // The caller will have checked we have this byte already for us - assert(ctx.enough_size(1)); - ctx.advance(1); - - // Number of fields - auto num_fields = meta.size(); - output.resize(old_size + num_fields); - - // Null bitmap - null_bitmap_traits null_bitmap (binary_row_null_bitmap_offset, num_fields); - const std::uint8_t* null_bitmap_begin = ctx.first(); - if (!ctx.enough_size(null_bitmap.byte_count())) - return make_error_code(errc::incomplete_message); - ctx.advance(null_bitmap.byte_count()); - - // Actual values - for (std::vector::size_type i = 0; i < output.size(); ++i) - { - if (null_bitmap.is_null(null_bitmap_begin, i)) - { - output[old_size + i] = field_view(nullptr); - } - else - { - auto err = deserialize_binary_field(ctx, meta[i], buffer_first, output[old_size + i]); - if (err != errc::ok) - return make_error_code(err); - } - } - - // Check for remaining bytes - if (!ctx.empty()) - return make_error_code(errc::extra_bytes); - - return error_code(); -} - - #endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP_ */ diff --git a/include/boost/mysql/detail/protocol/impl/deserialize_row.ipp b/include/boost/mysql/detail/protocol/impl/deserialize_row.ipp new file mode 100644 index 00000000..e7036e92 --- /dev/null +++ b/include/boost/mysql/detail/protocol/impl/deserialize_row.ipp @@ -0,0 +1,177 @@ +// +// Copyright (c) 2019-2022 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) +// + +#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_ROW_IPP +#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_ROW_IPP + +#pragma once + +#include +#include +#include +#include +#include + +namespace boost { +namespace mysql { +namespace detail { + +inline bool is_next_field_null( + const deserialization_context& ctx +) +{ + if (!ctx.enough_size(1)) + return false; + return *ctx.first() == 0xfb; +} + +inline error_code deserialize_text_row( + deserialization_context& ctx, + const std::vector& fields, + const std::uint8_t* buffer_first, + std::vector& output +) +{ + std::size_t old_size = output.size(); + output.resize(old_size + fields.size()); + for (std::vector::size_type i = 0; i < fields.size(); ++i) + { + if (is_next_field_null(ctx)) + { + ctx.advance(1); + output[old_size + i] = field_view(nullptr); + } + else + { + string_lenenc value_str; + errc err = deserialize(ctx, value_str); + if (err != errc::ok) + return make_error_code(err); + err = deserialize_text_field(value_str.value, fields[i], buffer_first, output[old_size + i]); + if (err != errc::ok) + return make_error_code(err); + } + } + if (!ctx.empty()) + return make_error_code(errc::extra_bytes); + return error_code(); +} + + +inline error_code deserialize_binary_row( + deserialization_context& ctx, + const std::vector& meta, + const std::uint8_t* buffer_first, + std::vector& output +) +{ + std::size_t old_size = output.size(); + + // Skip packet header (it is not part of the message in the binary + // protocol but it is in the text protocol, so we include it for homogeneity) + // The caller will have checked we have this byte already for us + assert(ctx.enough_size(1)); + ctx.advance(1); + + // Number of fields + auto num_fields = meta.size(); + output.resize(old_size + num_fields); + + // Null bitmap + null_bitmap_traits null_bitmap (binary_row_null_bitmap_offset, num_fields); + const std::uint8_t* null_bitmap_begin = ctx.first(); + if (!ctx.enough_size(null_bitmap.byte_count())) + return make_error_code(errc::incomplete_message); + ctx.advance(null_bitmap.byte_count()); + + // Actual values + for (std::vector::size_type i = 0; i < output.size(); ++i) + { + if (null_bitmap.is_null(null_bitmap_begin, i)) + { + output[old_size + i] = field_view(nullptr); + } + else + { + auto err = deserialize_binary_field(ctx, meta[i], buffer_first, output[old_size + i]); + if (err != errc::ok) + return make_error_code(err); + } + } + + // Check for remaining bytes + if (!ctx.empty()) + return make_error_code(errc::extra_bytes); + + return error_code(); +} + +} // detail +} // mysql +} // boost + +void boost::mysql::detail::deserialize_row( + resultset_encoding encoding, + deserialization_context& ctx, + const std::vector& meta, + const std::uint8_t* buffer_first, + std::vector& output, + error_code& err +) +{ + err = encoding == detail::resultset_encoding::text ? + deserialize_text_row(ctx, meta, buffer_first, output) : + deserialize_binary_row(ctx, meta, buffer_first, output); +} + +bool boost::mysql::detail::deserialize_row( + boost::asio::const_buffer read_message, + capabilities current_capabilities, + const std::uint8_t* buffer_first, // to store strings as offsets and allow buffer reallocation + resultset_base& result, + std::vector& output, + error_code& err, + error_info& info +) +{ + assert(result.valid()); + + // Message type: row, error or eof? + std::uint8_t msg_type = 0; + deserialization_context ctx (read_message, current_capabilities); + err = make_error_code(deserialize(ctx, msg_type)); + if (err) + return false; + if (msg_type == eof_packet_header) + { + // end of resultset => this is a ok_packet, not a row + ok_packet ok_pack; + err = deserialize_message(ctx, ok_pack); + if (err) + return false; + result.complete(ok_pack); + output.clear(); // TODO: this is wrong + return false; + } + else if (msg_type == error_packet_header) + { + // An error occurred during the generation of the rows + err = process_error_packet(ctx, info); + return false; + } + else + { + // An actual row + ctx.rewind(1); // keep the 'message type' byte, as it is part of the actual message + deserialize_row(result.encoding(), ctx, result.meta(), buffer_first, output, err); + if (err) + return false; + return true; + } +} + +#endif diff --git a/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp b/include/boost/mysql/detail/protocol/impl/deserialize_text_field.ipp similarity index 87% rename from include/boost/mysql/detail/protocol/impl/text_deserialization.ipp rename to include/boost/mysql/detail/protocol/impl/deserialize_text_field.ipp index 81373aaf..87e6eee3 100644 --- a/include/boost/mysql/detail/protocol/impl/text_deserialization.ipp +++ b/include/boost/mysql/detail/protocol/impl/deserialize_text_field.ipp @@ -5,12 +5,12 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_TEXT_DESERIALIZATION_IPP -#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_TEXT_DESERIALIZATION_IPP +#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_TEXT_FIELD_IPP +#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_TEXT_FIELD_IPP #pragma once -#include +#include #include #include #include @@ -296,20 +296,11 @@ inline errc deserialize_text_value_time( return errc::ok; } -inline bool is_next_field_null( - const deserialization_context& ctx -) -{ - if (!ctx.enough_size(1)) - return false; - return *ctx.first() == 0xfb; -} - } // detail } // mysql } // boost -inline boost::mysql::errc boost::mysql::detail::deserialize_text_value( +inline boost::mysql::errc boost::mysql::detail::deserialize_text_field( boost::string_view from, const metadata& meta, const std::uint8_t* buffer_first, @@ -358,38 +349,6 @@ inline boost::mysql::errc boost::mysql::detail::deserialize_text_value( } -boost::mysql::error_code boost::mysql::detail::deserialize_text_row( - deserialization_context& ctx, - const std::vector& fields, - const std::uint8_t* buffer_first, - std::vector& output -) -{ - std::size_t old_size = output.size(); - output.resize(old_size + fields.size()); - for (std::vector::size_type i = 0; i < fields.size(); ++i) - { - if (is_next_field_null(ctx)) - { - ctx.advance(1); - output[old_size + i] = field_view(nullptr); - } - else - { - string_lenenc value_str; - errc err = deserialize(ctx, value_str); - if (err != errc::ok) - return make_error_code(err); - err = deserialize_text_value(value_str.value, fields[i], buffer_first, output[old_size + i]); - if (err != errc::ok) - return make_error_code(err); - } - } - if (!ctx.empty()) - return make_error_code(errc::extra_bytes); - return error_code(); -} - #ifdef BOOST_MSVC #pragma warning( pop ) #endif diff --git a/include/boost/mysql/field_view.hpp b/include/boost/mysql/field_view.hpp index 03c01956..831ec1b6 100644 --- a/include/boost/mysql/field_view.hpp +++ b/include/boost/mysql/field_view.hpp @@ -8,6 +8,7 @@ #ifndef BOOST_MYSQL_FIELD_VIEW_HPP #define BOOST_MYSQL_FIELD_VIEW_HPP +#include #include #include #include @@ -182,6 +183,10 @@ private: BOOST_CXX14_CONSTEXPR date get_date() const noexcept { return date(date::duration(date_));} BOOST_CXX14_CONSTEXPR datetime get_datetime() const noexcept { return datetime(datetime::duration(datetime_)); } BOOST_CXX14_CONSTEXPR time get_time() const noexcept { return time(time_); } + BOOST_CXX14_CONSTEXPR detail::string_view_offset get_sv_offset() const noexcept + { + return detail::string_view_offset(sv_offset.offset, sv_offset.size); + } }; internal_kind ikind_ { internal_kind::null }; diff --git a/include/boost/mysql/impl/field_view.hpp b/include/boost/mysql/impl/field_view.hpp index 133daa2e..36dad1a1 100644 --- a/include/boost/mysql/impl/field_view.hpp +++ b/include/boost/mysql/impl/field_view.hpp @@ -214,7 +214,7 @@ BOOST_CXX14_CONSTEXPR inline boost::mysql::field_kind boost::mysql::field_view:: case internal_kind::time: return field_kind::time; case internal_kind::field_ptr: return repr_.field_ptr->kind(); // sv_offset values must be converted via offset_to_string_view before calling any other fn - default: assert(false); return field_kind::null; + default: return field_kind::null; } } @@ -350,6 +350,13 @@ BOOST_CXX14_CONSTEXPR bool boost::mysql::field_view::operator==( const field_view& rhs ) const noexcept { + // Make operator== work for types not representable by field_kind + if (ikind_ == internal_kind::sv_offset) + { + return rhs.ikind_ == internal_kind::sv_offset && + repr_.get_sv_offset() == rhs.repr_.get_sv_offset(); + } + auto k = kind(), rhs_k = rhs.kind(); switch (k) { @@ -401,6 +408,10 @@ inline std::ostream& boost::mysql::operator<<( const field_view& value ) { + // Make operator<< work for detail::string_view_offset types + if (value.ikind_ == field_view::internal_kind::sv_offset) + return os << ""; + switch (value.kind()) { case field_kind::null: return os << ""; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c2fed7af..1ff68e1b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,11 +37,11 @@ add_executable( unit/detail/auxiliar/static_string.cpp unit/detail/auxiliar/rows_iterator.cpp unit/detail/auxiliar/field_type_traits.cpp - # unit/detail/protocol/capabilities.cpp + unit/detail/protocol/capabilities.cpp # unit/detail/protocol/date.cpp - # unit/detail/protocol/null_bitmap_traits.cpp - # unit/detail/protocol/serialization_test.cpp - # unit/detail/protocol/text_deserialization_value.cpp + unit/detail/protocol/null_bitmap_traits.cpp + unit/detail/protocol/serialization_test.cpp + unit/detail/protocol/deserialize_text_field.cpp # unit/detail/protocol/text_deserialization_error.cpp # unit/detail/protocol/binary_deserialization_value.cpp # unit/detail/protocol/binary_deserialization_error.cpp diff --git a/test/unit/detail/protocol/text_deserialization_value.cpp b/test/unit/detail/protocol/deserialize_text_field.cpp similarity index 56% rename from test/unit/detail/protocol/text_deserialization_value.cpp rename to test/unit/detail/protocol/deserialize_text_field.cpp index 98483706..a412045f 100644 --- a/test/unit/detail/protocol/text_deserialization_value.cpp +++ b/test/unit/detail/protocol/deserialize_text_field.cpp @@ -7,10 +7,14 @@ // Test deserialize_text_value(), just positive cases -#include +#include +#include +#include "boost/mysql/detail/auxiliar/string_view_offset.hpp" +#include "boost/mysql/field_view.hpp" #include "test_common.hpp" #include #include +#include using namespace boost::mysql::detail; using namespace boost::mysql::test; @@ -22,7 +26,12 @@ using boost::mysql::errc; namespace { -struct text_value_sample +BOOST_AUTO_TEST_SUITE(test_deserialize_text_field) + +// Success cases +BOOST_AUTO_TEST_SUITE(success) + +struct success_sample { std::string name; std::string from; @@ -32,7 +41,7 @@ struct text_value_sample std::uint16_t flags; template - text_value_sample( + success_sample( std::string&& name, std::string&& from, T&& expected_value, @@ -50,7 +59,7 @@ struct text_value_sample } }; -std::ostream& operator<<(std::ostream& os, const text_value_sample& input) +std::ostream& operator<<(std::ostream& os, const success_sample& input) { return os << "(input=" << input.from << ", type=" << to_string(input.type) @@ -58,7 +67,7 @@ std::ostream& operator<<(std::ostream& os, const text_value_sample& input) << ")"; } -void add_string_samples(std::vector& output) +void add_string_samples(std::vector& output) { output.emplace_back("varchar_non_empty", "string", "string", protocol_field_type::var_string); output.emplace_back("varchar_empty", "", "", protocol_field_type::var_string); @@ -88,7 +97,7 @@ void add_int_samples_helper( std::string zerofill_s, std::uint64_t zerofill_b, protocol_field_type type, - std::vector& output + std::vector& output ) { output.emplace_back("signed", "20", std::int64_t(20), type); @@ -103,7 +112,7 @@ void add_int_samples_helper( zerofill_b, type, column_flags::unsigned_ | column_flags::zerofill); } -void add_int_samples(std::vector& output) +void add_int_samples(std::vector& output) { add_int_samples_helper( "127", 127, @@ -162,7 +171,7 @@ void add_int_samples(std::vector& output) } // bit -void add_bit_types(std::vector& output) +void add_bit_types(std::vector& output) { output.emplace_back("bit_8", "\x12", std::uint64_t(0x12), protocol_field_type::bit, column_flags::unsigned_); @@ -185,7 +194,7 @@ void add_bit_types(std::vector& output) template void add_float_samples( protocol_field_type type, - std::vector& output + std::vector& output ) { output.emplace_back("zero", "0", T(0.0), type); @@ -203,7 +212,7 @@ void add_float_samples( output.emplace_back("negative_exponent_negative_fractional", "-3.45e-20", T(-3.45e-20), type); } -void add_date_samples(std::vector& output) +void add_date_samples(std::vector& output) { output.emplace_back("regular_date", "2019-02-28", makedate(2019, 2, 28), protocol_field_type::date); output.emplace_back("leap_year", "1788-02-29", makedate(1788, 2, 29), protocol_field_type::date); @@ -218,7 +227,7 @@ void add_date_samples(std::vector& output) void add_datetime_samples( protocol_field_type type, - std::vector& output + std::vector& output ) { output.emplace_back("0_decimals_date", "2010-02-15 00:00:00", makedt(2010, 2, 15), type); @@ -264,7 +273,8 @@ void add_datetime_samples( // not a real case, we cap decimals to 6 output.emplace_back("7_decimals", "2010-02-15 02:05:30.002395", makedt(2010, 2, 15, 2, 5, 30, 2395), type, 0, 7); - // Generate all invalid date casuistic for all decimals + // Generate all invalid date casuistic for all decimals. + // These are accepted by MySQL depending on the configuration constexpr struct { const char* name; @@ -294,7 +304,7 @@ void add_datetime_samples( } } -void add_time_samples(std::vector& output) +void add_time_samples(std::vector& output) { output.emplace_back("0_decimals_positive_h", "01:00:00", maket(1, 0, 0), protocol_field_type::time); output.emplace_back("0_decimals_positive_hm", "12:03:00", maket(12, 3, 0), protocol_field_type::time); @@ -365,9 +375,9 @@ void add_time_samples(std::vector& output) output.emplace_back("7_decimals", "14:51:23.501717", maket(14, 51, 23, 501717), protocol_field_type::time, 0, 7); } -std::vector make_all_samples() +std::vector make_all_samples() { - std::vector res; + std::vector res; add_string_samples(res); add_int_samples(res); add_bit_types(res); @@ -380,17 +390,291 @@ std::vector make_all_samples() return res; } -BOOST_DATA_TEST_CASE(test_deserialize_text_value_ok, data::make(make_all_samples())) +BOOST_DATA_TEST_CASE(ok, data::make(make_all_samples())) { column_definition_packet coldef {}; coldef.type = sample.type; coldef.decimals = static_cast(sample.decimals); coldef.flags = sample.flags; - boost::mysql::metadata meta (coldef); + boost::mysql::metadata meta (coldef, false); + const std::uint8_t* buffer_first = reinterpret_cast(sample.from.data()); field_view actual_value; - auto err = deserialize_text_value(sample.from, meta, actual_value); + + auto err = deserialize_text_field( + sample.from, + meta, + buffer_first, + actual_value + ); BOOST_TEST(err == errc::ok); + + // Strings are representd as string view offsets + if (sample.expected.is_string()) + { + field_view expected_offset (string_view_offset(0, sample.expected.get_string().size())); + BOOST_TEST(actual_value == expected_offset); + actual_value.offset_to_string_view(buffer_first); + } + BOOST_TEST(actual_value == sample.expected); } +BOOST_AUTO_TEST_SUITE_END() + +// +// Error cases +// + +BOOST_AUTO_TEST_SUITE(errors) + +struct error_sample +{ + std::string name; + boost::string_view from; + protocol_field_type type; + std::uint16_t flags; + unsigned decimals; + errc expected_err; + + error_sample(std::string&& name, boost::string_view from, protocol_field_type type, + std::uint16_t flags=0, unsigned decimals=0, errc expected_err=errc::protocol_value_error) : + name(std::move(name)), + from(from), + type(type), + flags(flags), + decimals(decimals), + expected_err(expected_err) + { + } +}; + +std::ostream& operator<<(std::ostream& os, const error_sample& input) +{ + return os << "(input=" << input.from + << ", type=" << to_string(input.type) + << ", name=" << input.name + << ")"; +} + +void add_int_samples( + protocol_field_type t, + std::vector& output +) +{ + output.emplace_back("signed_blank", "", t); + output.emplace_back("signed_non_number", "abtrf", t); + output.emplace_back("signed_hex", "0x01", t); + output.emplace_back("signed_fractional", "1.1", t); + output.emplace_back("signed_exp", "2e10", t); + output.emplace_back("signed_lt_min", "-9223372036854775809", t); + output.emplace_back("signed_gt_max", "9223372036854775808", t); + output.emplace_back("unsigned_blank", "", t, column_flags::unsigned_); + output.emplace_back("unsigned_non_number", "abtrf", t, column_flags::unsigned_); + output.emplace_back("unsigned_hex", "0x01", t, column_flags::unsigned_); + output.emplace_back("unsigned_fractional", "1.1", t, column_flags::unsigned_); + output.emplace_back("unsigned_exp", "2e10", t, column_flags::unsigned_); + output.emplace_back("unsigned_lt_min", "-18446744073709551616", t, column_flags::unsigned_); + output.emplace_back("unsigned_gt_max", "18446744073709551616", t, column_flags::unsigned_); +} + +void add_bit_samples( + std::vector& output +) +{ + output.emplace_back("bit_string_view_too_short", "", protocol_field_type::bit, column_flags::unsigned_); + output.emplace_back("bit_string_view_too_long", "123456789", protocol_field_type::bit, column_flags::unsigned_); +} + +void add_float_samples( + protocol_field_type t, + boost::string_view lt_min, + boost::string_view gt_max, + std::vector& output +) +{ + output.emplace_back("blank", "", t); + output.emplace_back("non_number", "abtrf", t); + output.emplace_back("lt_min", lt_min, t); + output.emplace_back("gt_max", gt_max, t); + output.emplace_back("inf", "inf", t); // inf values not allowed by SQL std + output.emplace_back("minus_inf", "-inf", t); + output.emplace_back("nan", "nan", t); // nan values not allowed by SQL std + output.emplace_back("minus_nan", "-nan", t); +} + +void add_date_samples(std::vector& output) +{ + output.emplace_back("empty", "", protocol_field_type::date); + output.emplace_back("too_short", "2020-05-2", protocol_field_type::date); + output.emplace_back("too_long", "02020-05-02", protocol_field_type::date); + output.emplace_back("bad_delimiter", "2020:05:02", protocol_field_type::date); + output.emplace_back("too_many_groups", "20-20-05-2", protocol_field_type::date); + output.emplace_back("too_few_groups", "2020-00005", protocol_field_type::date); + output.emplace_back("incomplete_year", "999-05-005", protocol_field_type::date); + output.emplace_back("hex", "ffff-ff-ff", protocol_field_type::date); + output.emplace_back("null_value", makesv("2020-05-\02"), protocol_field_type::date); + output.emplace_back("long_year", "10000-05-2", protocol_field_type::date); + output.emplace_back("long_month", "2010-005-2", protocol_field_type::date); + output.emplace_back("long_day", "2010-5-002", protocol_field_type::date); + output.emplace_back("negative_year", "-001-05-02", protocol_field_type::date); + output.emplace_back("invalid_month", "2010-13-02", protocol_field_type::date); + output.emplace_back("invalid_month_max","2010-99-02", protocol_field_type::date); + output.emplace_back("negative_month", "2010--5-02", protocol_field_type::date); + output.emplace_back("invalid_day", "2010-05-32", protocol_field_type::date); + output.emplace_back("invalid_day_max", "2010-05-99", protocol_field_type::date); + output.emplace_back("negative_day", "2010-05--2", protocol_field_type::date); +} + +void add_datetime_samples( + protocol_field_type t, + std::vector& output +) +{ + output.emplace_back("empty", "", t); + output.emplace_back("too_short_0", "2020-05-02 23:01:0", t, 0, 0); + output.emplace_back("too_short_1", "2020-05-02 23:01:0.1", t, 0, 1); + output.emplace_back("too_short_2", "2020-05-02 23:01:00.1", t, 0, 2); + output.emplace_back("too_short_3", "2020-05-02 23:01:00.11", t, 0, 3); + output.emplace_back("too_short_4", "2020-05-02 23:01:00.111", t, 0, 4); + output.emplace_back("too_short_5", "2020-05-02 23:01:00.1111", t, 0, 5); + output.emplace_back("too_short_6", "2020-05-02 23:01:00.11111", t, 0, 6); + output.emplace_back("too_long_0", "2020-05-02 23:01:00.8", t, 0, 0); + output.emplace_back("too_long_1", "2020-05-02 23:01:00.98", t, 0, 1); + output.emplace_back("too_long_2", "2020-05-02 23:01:00.998", t, 0, 2); + output.emplace_back("too_long_3", "2020-05-02 23:01:00.9998", t, 0, 3); + output.emplace_back("too_long_4", "2020-05-02 23:01:00.99998", t, 0, 4); + output.emplace_back("too_long_5", "2020-05-02 23:01:00.999998", t, 0, 5); + output.emplace_back("too_long_6", "2020-05-02 23:01:00.9999998", t, 0, 6); + output.emplace_back("no_decimals_1", "2020-05-02 23:01:00 ", t, 0, 1); + output.emplace_back("no_decimals_2", "2020-05-02 23:01:00 ", t, 0, 2); + output.emplace_back("no_decimals_3", "2020-05-02 23:01:00 ", t, 0, 3); + output.emplace_back("no_decimals_4", "2020-05-02 23:01:00 ", t, 0, 4); + output.emplace_back("no_decimals_5", "2020-05-02 23:01:00 ", t, 0, 5); + output.emplace_back("no_decimals_6", "2020-05-02 23:01:00 ", t, 0, 6); + output.emplace_back("trailing_0", "2020-05-02 23:01:0p", t, 0, 0); + output.emplace_back("trailing_1", "2020-05-02 23:01:00.p", t, 0, 1); + output.emplace_back("trailing_2", "2020-05-02 23:01:00.1p", t, 0, 2); + output.emplace_back("trailing_3", "2020-05-02 23:01:00.12p", t, 0, 3); + output.emplace_back("trailing_4", "2020-05-02 23:01:00.123p", t, 0, 4); + output.emplace_back("trailing_5", "2020-05-02 23:01:00.1234p", t, 0, 5); + output.emplace_back("trailing_6", "2020-05-02 23:01:00.12345p", t, 0, 6); + output.emplace_back("bad_delimiter", "2020-05-02 23-01-00", t); + output.emplace_back("missing_1gp_0", "2020-05-02 23:01: ", t); + output.emplace_back("missing_2gp_0", "2020-05-02 23: ", t); + output.emplace_back("missing_3gp_0", "2020-05-02 ", t); + output.emplace_back("missing_1gp_1", "2020-05-02 23:01:.9 ", t); + output.emplace_back("missing_2gp_1", "2020-05-02 23:.9 ", t); + output.emplace_back("missing_3gp_1", "2020-05-02.9 ", t); + output.emplace_back("invalid_year", "10000-05-02 24:20:20.1", t, 0, 2); + output.emplace_back("negative_year", "-100-05-02 24:20:20", t); + output.emplace_back("invalid_month", "2020-13-02 24:20:20", t); + output.emplace_back("negative_month", "2020--5-02 24:20:20", t); + output.emplace_back("invalid_day", "2020-05-32 24:20:20", t); + output.emplace_back("negative_day", "2020-05--2 24:20:20", t); + output.emplace_back("invalid_hour", "2020-05-02 24:20:20", t); + output.emplace_back("negative_hour", "2020-05-02 -2:20:20", t); + output.emplace_back("invalid_min", "2020-05-02 22:60:20", t); + output.emplace_back("negative_min", "2020-05-02 22:-1:20", t); + output.emplace_back("invalid_sec", "2020-05-02 22:06:60", t); + output.emplace_back("negative_sec", "2020-05-02 22:06:-1", t); + output.emplace_back("negative_micro_2", "2020-05-02 22:06:01.-1", t, 0, 2); + output.emplace_back("negative_micro_3", "2020-05-02 22:06:01.-12", t, 0, 3); + output.emplace_back("negative_micro_4", "2020-05-02 22:06:01.-123", t, 0, 4); + output.emplace_back("negative_micro_5", "2020-05-02 22:06:01.-1234", t, 0, 5); + output.emplace_back("negative_micro_6", "2020-05-02 22:06:01.-12345", t, 0, 6); +} + +void add_time_samples(std::vector& output) +{ + output.emplace_back("empty", "", protocol_field_type::time); + output.emplace_back("not_numbers", "abjkjdb67", protocol_field_type::time); + output.emplace_back("too_short_0", "1:20:20", protocol_field_type::time); + output.emplace_back("too_short_1", "1:20:20.1", protocol_field_type::time, 0, 1); + output.emplace_back("too_short_2", "01:20:20.1", protocol_field_type::time, 0, 2); + output.emplace_back("too_short_3", "01:20:20.12", protocol_field_type::time, 0, 3); + output.emplace_back("too_short_4", "01:20:20.123", protocol_field_type::time, 0, 4); + output.emplace_back("too_short_5", "01:20:20.1234", protocol_field_type::time, 0, 5); + output.emplace_back("too_short_6", "01:20:20.12345", protocol_field_type::time, 0, 6); + output.emplace_back("too_long_0", "-9999:40:40", protocol_field_type::time, 0, 0); + output.emplace_back("too_long_1", "-9999:40:40.1", protocol_field_type::time, 0, 1); + output.emplace_back("too_long_2", "-9999:40:40.12", protocol_field_type::time, 0, 2); + output.emplace_back("too_long_3", "-9999:40:40.123", protocol_field_type::time, 0, 3); + output.emplace_back("too_long_4", "-9999:40:40.1234", protocol_field_type::time, 0, 4); + output.emplace_back("too_long_5", "-9999:40:40.12345", protocol_field_type::time, 0, 5); + output.emplace_back("too_long_6", "-9999:40:40.123456", protocol_field_type::time, 0, 6); + output.emplace_back("extra_long", "-99999999:40:40.12345678", protocol_field_type::time, 0, 6); + output.emplace_back("extra_long2", "99999999999:40:40", protocol_field_type::time, 0, 6); + output.emplace_back("decimals_0", "01:20:20.1", protocol_field_type::time, 0, 0); + output.emplace_back("no_decimals_1", "01:20:20 ", protocol_field_type::time, 0, 1); + output.emplace_back("no_decimals_2", "01:20:20 ", protocol_field_type::time, 0, 2); + output.emplace_back("no_decimals_3", "01:20:20 ", protocol_field_type::time, 0, 3); + output.emplace_back("no_decimals_4", "01:20:20 ", protocol_field_type::time, 0, 4); + output.emplace_back("no_decimals_5", "01:20:20 ", protocol_field_type::time, 0, 5); + output.emplace_back("no_decimals_6", "01:20:20 ", protocol_field_type::time, 0, 6); + output.emplace_back("bad_delimiter", "01-20-20", protocol_field_type::time); + output.emplace_back("missing_1gp_0", "23:01: ", protocol_field_type::time); + output.emplace_back("missing_2gp_0", "23: ", protocol_field_type::time); + output.emplace_back("missing_1gp_1", "23:01:.9 ", protocol_field_type::time, 0, 1); + output.emplace_back("missing_2gp_1", "23:.9 ", protocol_field_type::time, 0, 1); + output.emplace_back("invalid_min", "22:60:20", protocol_field_type::time); + output.emplace_back("negative_min", "22:-1:20", protocol_field_type::time); + output.emplace_back("invalid_sec", "22:06:60", protocol_field_type::time); + output.emplace_back("negative_sec", "22:06:-1", protocol_field_type::time); + output.emplace_back("invalid_micro_1", "22:06:01.99", protocol_field_type::time, 0, 1); + output.emplace_back("invalid_micro_2", "22:06:01.999", protocol_field_type::time, 0, 2); + output.emplace_back("invalid_micro_3", "22:06:01.9999", protocol_field_type::time, 0, 3); + output.emplace_back("invalid_micro_4", "22:06:01.99999", protocol_field_type::time, 0, 4); + output.emplace_back("invalid_micro_5", "22:06:01.999999", protocol_field_type::time, 0, 5); + output.emplace_back("invalid_micro_6", "22:06:01.9999999", protocol_field_type::time, 0, 6); + output.emplace_back("negative_micro", "22:06:01.-1", protocol_field_type::time, 0, 2); + output.emplace_back("lt_min", "-900:00:00.00", protocol_field_type::time, 0, 2); + output.emplace_back("gt_max", "900:00:00.00", protocol_field_type::time, 0, 2); + output.emplace_back("invalid_sign", "x670:00:00.00", protocol_field_type::time, 0, 2); + output.emplace_back("null_char", makesv("20:00:\00.00"), protocol_field_type::time, 0, 2); + output.emplace_back("trailing_0", "22:06:01k", protocol_field_type::time, 0, 0); + output.emplace_back("trailing_1", "22:06:01.1k", protocol_field_type::time, 0, 1); + output.emplace_back("trailing_2", "22:06:01.12k", protocol_field_type::time, 0, 2); + output.emplace_back("trailing_3", "22:06:01.123k", protocol_field_type::time, 0, 3); + output.emplace_back("trailing_4", "22:06:01.1234k", protocol_field_type::time, 0, 4); + output.emplace_back("trailing_5", "22:06:01.12345k", protocol_field_type::time, 0, 5); + output.emplace_back("trailing_6", "22:06:01.123456k", protocol_field_type::time, 0, 6); + output.emplace_back("double_sign", "--22:06:01.123456", protocol_field_type::time, 0, 6); +} + +std::vector make_all_samples() +{ + std::vector res; + add_int_samples(protocol_field_type::tiny, res); + add_int_samples(protocol_field_type::short_, res); + add_int_samples(protocol_field_type::int24, res); + add_int_samples(protocol_field_type::long_, res); + add_int_samples(protocol_field_type::longlong, res); + add_int_samples(protocol_field_type::year, res); + add_bit_samples(res); + add_float_samples(protocol_field_type::float_, "-2e90", "2e90", res); + add_float_samples(protocol_field_type::double_, "-2e9999", "2e9999", res); + add_date_samples(res); + add_datetime_samples(protocol_field_type::datetime, res); + add_datetime_samples(protocol_field_type::timestamp, res); + add_time_samples(res); + return res; +} + +BOOST_DATA_TEST_CASE(error, data::make(make_all_samples())) +{ + column_definition_packet coldef {}; + coldef.type = sample.type; + coldef.decimals = static_cast(sample.decimals); + coldef.flags = sample.flags; + boost::mysql::metadata meta (coldef, false); + auto buffer_first = reinterpret_cast(sample.from.data()); + field_view actual_value; + auto err = deserialize_text_field(sample.from, meta, buffer_first, actual_value); + BOOST_TEST(err == sample.expected_err); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() + } // anon namespace diff --git a/test/unit/detail/protocol/serialization_test_samples/prepared_statement_messages.hpp b/test/unit/detail/protocol/serialization_test_samples/prepared_statement_messages.hpp index 6f805a83..223d5bf8 100644 --- a/test/unit/detail/protocol/serialization_test_samples/prepared_statement_messages.hpp +++ b/test/unit/detail/protocol/serialization_test_samples/prepared_statement_messages.hpp @@ -9,6 +9,7 @@ #define BOOST_MYSQL_TEST_UNIT_DETAIL_PROTOCOL_SERIALIZATION_TEST_SAMPLES_PREPARED_STATEMENT_MESSAGES_HPP #include +#include #include "../serialization_test.hpp" #include #include @@ -79,7 +80,7 @@ serialization_sample make_stmt_execute_sample( const serialization_test_spec com_stmt_execute_packet_spec { serialization_test_type::serialization, { make_stmt_execute_sample(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params - make_values(std::uint64_t(0xabffffabacadae)), { + make_field_views(std::uint64_t(0xabffffabacadae)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x80, 0xae, 0xad, 0xac, 0xab, 0xff, 0xff, 0xab, 0x00 @@ -87,7 +88,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "uint64_t" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(std::int64_t(-0xabffffabacadae)), { + make_field_views(std::int64_t(-0xabffffabacadae)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x52, 0x52, 0x53, 0x54, 0x00, 0x00, 0x54, 0xff @@ -95,7 +96,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "int64_t" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(boost::string_view("test")), { + make_field_views(boost::string_view("test")), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74 @@ -103,7 +104,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "string_view" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(3.14e20f), { + make_field_views(3.14e20f), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x2d, 0x88, 0x61 @@ -111,7 +112,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "float" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(2.1e214), { + make_field_views(2.1e214), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x56, 0xc0, 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c @@ -119,7 +120,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "double" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(makedate(2010, 9, 3)), { + make_field_views(makedate(2010, 9, 3)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x04, 0xda, 0x07, 0x09, 0x03 @@ -127,7 +128,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "date" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(makedt(2010, 9, 3, 10, 30, 59, 231800)), { + make_field_views(makedt(2010, 9, 3, 10, 30, 59, 231800)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x0b, 0xda, 0x07, 0x09, 0x03, 0x0a, 0x1e, 0x3b, 0x78, 0x89, @@ -136,7 +137,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "datetime" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(maket(230, 30, 59, 231800)), { + make_field_views(maket(230, 30, 59, 231800)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x1e, 0x3b, 0x78, @@ -145,14 +146,14 @@ const serialization_test_spec com_stmt_execute_packet_spec { "time" ), make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params - make_values(nullptr), { + make_field_views(nullptr), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00 }, "null" ), make_stmt_execute_sample(2, 0, 1, 1, - make_values( + make_field_views( std::uint64_t(0xabffffabacadae), std::int64_t(-0xabffffabacadae), boost::string_view("test"), @@ -178,7 +179,7 @@ const serialization_test_spec com_stmt_execute_packet_spec { "several_params" ), make_stmt_execute_sample<1, std::forward_list>(1, 0x80, 1, 1, - make_values(std::uint64_t(0xabffff)), { + make_field_views(std::uint64_t(0xabffff)), { 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x80, 0xff, 0xff, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00 diff --git a/test/unit/detail/protocol/text_deserialization_error.cpp b/test/unit/detail/protocol/text_deserialization_error.cpp deleted file mode 100644 index d849ea41..00000000 --- a/test/unit/detail/protocol/text_deserialization_error.cpp +++ /dev/null @@ -1,271 +0,0 @@ -// -// Copyright (c) 2019-2022 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_text_value(), only error cases - -#include -#include "test_common.hpp" -#include -#include - -using namespace boost::mysql::detail; -using namespace boost::mysql::test; -using namespace boost::unit_test; -using boost::mysql::field_view; -using boost::mysql::error_code; -using boost::mysql::errc; - -namespace -{ - -struct text_value_err_sample -{ - std::string name; - boost::string_view from; - protocol_field_type type; - std::uint16_t flags; - unsigned decimals; - errc expected_err; - - text_value_err_sample(std::string&& name, boost::string_view from, protocol_field_type type, - std::uint16_t flags=0, unsigned decimals=0, errc expected_err=errc::protocol_value_error) : - name(std::move(name)), - from(from), - type(type), - flags(flags), - decimals(decimals), - expected_err(expected_err) - { - } -}; - -std::ostream& operator<<(std::ostream& os, const text_value_err_sample& input) -{ - return os << "(input=" << input.from - << ", type=" << to_string(input.type) - << ", name=" << input.name - << ")"; -} - -void add_int_samples( - protocol_field_type t, - std::vector& output -) -{ - output.emplace_back("signed_blank", "", t); - output.emplace_back("signed_non_number", "abtrf", t); - output.emplace_back("signed_hex", "0x01", t); - output.emplace_back("signed_fractional", "1.1", t); - output.emplace_back("signed_exp", "2e10", t); - output.emplace_back("signed_lt_min", "-9223372036854775809", t); - output.emplace_back("signed_gt_max", "9223372036854775808", t); - output.emplace_back("unsigned_blank", "", t, column_flags::unsigned_); - output.emplace_back("unsigned_non_number", "abtrf", t, column_flags::unsigned_); - output.emplace_back("unsigned_hex", "0x01", t, column_flags::unsigned_); - output.emplace_back("unsigned_fractional", "1.1", t, column_flags::unsigned_); - output.emplace_back("unsigned_exp", "2e10", t, column_flags::unsigned_); - output.emplace_back("unsigned_lt_min", "-18446744073709551616", t, column_flags::unsigned_); - output.emplace_back("unsigned_gt_max", "18446744073709551616", t, column_flags::unsigned_); -} - -void add_bit_samples( - std::vector& output -) -{ - output.emplace_back("bit_string_view_too_short", "", protocol_field_type::bit, column_flags::unsigned_); - output.emplace_back("bit_string_view_too_long", "123456789", protocol_field_type::bit, column_flags::unsigned_); -} - -void add_float_samples( - protocol_field_type t, - boost::string_view lt_min, - boost::string_view gt_max, - std::vector& output -) -{ - output.emplace_back("blank", "", t); - output.emplace_back("non_number", "abtrf", t); - output.emplace_back("lt_min", lt_min, t); - output.emplace_back("gt_max", gt_max, t); - output.emplace_back("inf", "inf", t); // inf values not allowed by SQL std - output.emplace_back("minus_inf", "-inf", t); - output.emplace_back("nan", "nan", t); // nan values not allowed by SQL std - output.emplace_back("minus_nan", "-nan", t); -} - -void add_date_samples(std::vector& output) -{ - output.emplace_back("empty", "", protocol_field_type::date); - output.emplace_back("too_short", "2020-05-2", protocol_field_type::date); - output.emplace_back("too_long", "02020-05-02", protocol_field_type::date); - output.emplace_back("bad_delimiter", "2020:05:02", protocol_field_type::date); - output.emplace_back("too_many_groups", "20-20-05-2", protocol_field_type::date); - output.emplace_back("too_few_groups", "2020-00005", protocol_field_type::date); - output.emplace_back("incomplete_year", "999-05-005", protocol_field_type::date); - output.emplace_back("hex", "ffff-ff-ff", protocol_field_type::date); - output.emplace_back("null_value", makesv("2020-05-\02"), protocol_field_type::date); - output.emplace_back("long_year", "10000-05-2", protocol_field_type::date); - output.emplace_back("long_month", "2010-005-2", protocol_field_type::date); - output.emplace_back("long_day", "2010-5-002", protocol_field_type::date); - output.emplace_back("negative_year", "-001-05-02", protocol_field_type::date); - output.emplace_back("invalid_month", "2010-13-02", protocol_field_type::date); - output.emplace_back("invalid_month_max","2010-99-02", protocol_field_type::date); - output.emplace_back("negative_month", "2010--5-02", protocol_field_type::date); - output.emplace_back("invalid_day", "2010-05-32", protocol_field_type::date); - output.emplace_back("invalid_day_max", "2010-05-99", protocol_field_type::date); - output.emplace_back("negative_day", "2010-05--2", protocol_field_type::date); -} - -void add_datetime_samples( - protocol_field_type t, - std::vector& output -) -{ - output.emplace_back("empty", "", t); - output.emplace_back("too_short_0", "2020-05-02 23:01:0", t, 0, 0); - output.emplace_back("too_short_1", "2020-05-02 23:01:0.1", t, 0, 1); - output.emplace_back("too_short_2", "2020-05-02 23:01:00.1", t, 0, 2); - output.emplace_back("too_short_3", "2020-05-02 23:01:00.11", t, 0, 3); - output.emplace_back("too_short_4", "2020-05-02 23:01:00.111", t, 0, 4); - output.emplace_back("too_short_5", "2020-05-02 23:01:00.1111", t, 0, 5); - output.emplace_back("too_short_6", "2020-05-02 23:01:00.11111", t, 0, 6); - output.emplace_back("too_long_0", "2020-05-02 23:01:00.8", t, 0, 0); - output.emplace_back("too_long_1", "2020-05-02 23:01:00.98", t, 0, 1); - output.emplace_back("too_long_2", "2020-05-02 23:01:00.998", t, 0, 2); - output.emplace_back("too_long_3", "2020-05-02 23:01:00.9998", t, 0, 3); - output.emplace_back("too_long_4", "2020-05-02 23:01:00.99998", t, 0, 4); - output.emplace_back("too_long_5", "2020-05-02 23:01:00.999998", t, 0, 5); - output.emplace_back("too_long_6", "2020-05-02 23:01:00.9999998", t, 0, 6); - output.emplace_back("no_decimals_1", "2020-05-02 23:01:00 ", t, 0, 1); - output.emplace_back("no_decimals_2", "2020-05-02 23:01:00 ", t, 0, 2); - output.emplace_back("no_decimals_3", "2020-05-02 23:01:00 ", t, 0, 3); - output.emplace_back("no_decimals_4", "2020-05-02 23:01:00 ", t, 0, 4); - output.emplace_back("no_decimals_5", "2020-05-02 23:01:00 ", t, 0, 5); - output.emplace_back("no_decimals_6", "2020-05-02 23:01:00 ", t, 0, 6); - output.emplace_back("trailing_0", "2020-05-02 23:01:0p", t, 0, 0); - output.emplace_back("trailing_1", "2020-05-02 23:01:00.p", t, 0, 1); - output.emplace_back("trailing_2", "2020-05-02 23:01:00.1p", t, 0, 2); - output.emplace_back("trailing_3", "2020-05-02 23:01:00.12p", t, 0, 3); - output.emplace_back("trailing_4", "2020-05-02 23:01:00.123p", t, 0, 4); - output.emplace_back("trailing_5", "2020-05-02 23:01:00.1234p", t, 0, 5); - output.emplace_back("trailing_6", "2020-05-02 23:01:00.12345p", t, 0, 6); - output.emplace_back("bad_delimiter", "2020-05-02 23-01-00", t); - output.emplace_back("missing_1gp_0", "2020-05-02 23:01: ", t); - output.emplace_back("missing_2gp_0", "2020-05-02 23: ", t); - output.emplace_back("missing_3gp_0", "2020-05-02 ", t); - output.emplace_back("missing_1gp_1", "2020-05-02 23:01:.9 ", t); - output.emplace_back("missing_2gp_1", "2020-05-02 23:.9 ", t); - output.emplace_back("missing_3gp_1", "2020-05-02.9 ", t); - output.emplace_back("invalid_year", "10000-05-02 24:20:20.1", t, 0, 2); - output.emplace_back("negative_year", "-100-05-02 24:20:20", t); - output.emplace_back("invalid_month", "2020-13-02 24:20:20", t); - output.emplace_back("negative_month", "2020--5-02 24:20:20", t); - output.emplace_back("invalid_day", "2020-05-32 24:20:20", t); - output.emplace_back("negative_day", "2020-05--2 24:20:20", t); - output.emplace_back("invalid_hour", "2020-05-02 24:20:20", t); - output.emplace_back("negative_hour", "2020-05-02 -2:20:20", t); - output.emplace_back("invalid_min", "2020-05-02 22:60:20", t); - output.emplace_back("negative_min", "2020-05-02 22:-1:20", t); - output.emplace_back("invalid_sec", "2020-05-02 22:06:60", t); - output.emplace_back("negative_sec", "2020-05-02 22:06:-1", t); - output.emplace_back("negative_micro_2", "2020-05-02 22:06:01.-1", t, 0, 2); - output.emplace_back("negative_micro_3", "2020-05-02 22:06:01.-12", t, 0, 3); - output.emplace_back("negative_micro_4", "2020-05-02 22:06:01.-123", t, 0, 4); - output.emplace_back("negative_micro_5", "2020-05-02 22:06:01.-1234", t, 0, 5); - output.emplace_back("negative_micro_6", "2020-05-02 22:06:01.-12345", t, 0, 6); -} - -void add_time_samples(std::vector& output) -{ - output.emplace_back("empty", "", protocol_field_type::time); - output.emplace_back("not_numbers", "abjkjdb67", protocol_field_type::time); - output.emplace_back("too_short_0", "1:20:20", protocol_field_type::time); - output.emplace_back("too_short_1", "1:20:20.1", protocol_field_type::time, 0, 1); - output.emplace_back("too_short_2", "01:20:20.1", protocol_field_type::time, 0, 2); - output.emplace_back("too_short_3", "01:20:20.12", protocol_field_type::time, 0, 3); - output.emplace_back("too_short_4", "01:20:20.123", protocol_field_type::time, 0, 4); - output.emplace_back("too_short_5", "01:20:20.1234", protocol_field_type::time, 0, 5); - output.emplace_back("too_short_6", "01:20:20.12345", protocol_field_type::time, 0, 6); - output.emplace_back("too_long_0", "-9999:40:40", protocol_field_type::time, 0, 0); - output.emplace_back("too_long_1", "-9999:40:40.1", protocol_field_type::time, 0, 1); - output.emplace_back("too_long_2", "-9999:40:40.12", protocol_field_type::time, 0, 2); - output.emplace_back("too_long_3", "-9999:40:40.123", protocol_field_type::time, 0, 3); - output.emplace_back("too_long_4", "-9999:40:40.1234", protocol_field_type::time, 0, 4); - output.emplace_back("too_long_5", "-9999:40:40.12345", protocol_field_type::time, 0, 5); - output.emplace_back("too_long_6", "-9999:40:40.123456", protocol_field_type::time, 0, 6); - output.emplace_back("extra_long", "-99999999:40:40.12345678", protocol_field_type::time, 0, 6); - output.emplace_back("extra_long2", "99999999999:40:40", protocol_field_type::time, 0, 6); - output.emplace_back("decimals_0", "01:20:20.1", protocol_field_type::time, 0, 0); - output.emplace_back("no_decimals_1", "01:20:20 ", protocol_field_type::time, 0, 1); - output.emplace_back("no_decimals_2", "01:20:20 ", protocol_field_type::time, 0, 2); - output.emplace_back("no_decimals_3", "01:20:20 ", protocol_field_type::time, 0, 3); - output.emplace_back("no_decimals_4", "01:20:20 ", protocol_field_type::time, 0, 4); - output.emplace_back("no_decimals_5", "01:20:20 ", protocol_field_type::time, 0, 5); - output.emplace_back("no_decimals_6", "01:20:20 ", protocol_field_type::time, 0, 6); - output.emplace_back("bad_delimiter", "01-20-20", protocol_field_type::time); - output.emplace_back("missing_1gp_0", "23:01: ", protocol_field_type::time); - output.emplace_back("missing_2gp_0", "23: ", protocol_field_type::time); - output.emplace_back("missing_1gp_1", "23:01:.9 ", protocol_field_type::time, 0, 1); - output.emplace_back("missing_2gp_1", "23:.9 ", protocol_field_type::time, 0, 1); - output.emplace_back("invalid_min", "22:60:20", protocol_field_type::time); - output.emplace_back("negative_min", "22:-1:20", protocol_field_type::time); - output.emplace_back("invalid_sec", "22:06:60", protocol_field_type::time); - output.emplace_back("negative_sec", "22:06:-1", protocol_field_type::time); - output.emplace_back("invalid_micro_1", "22:06:01.99", protocol_field_type::time, 0, 1); - output.emplace_back("invalid_micro_2", "22:06:01.999", protocol_field_type::time, 0, 2); - output.emplace_back("invalid_micro_3", "22:06:01.9999", protocol_field_type::time, 0, 3); - output.emplace_back("invalid_micro_4", "22:06:01.99999", protocol_field_type::time, 0, 4); - output.emplace_back("invalid_micro_5", "22:06:01.999999", protocol_field_type::time, 0, 5); - output.emplace_back("invalid_micro_6", "22:06:01.9999999", protocol_field_type::time, 0, 6); - output.emplace_back("negative_micro", "22:06:01.-1", protocol_field_type::time, 0, 2); - output.emplace_back("lt_min", "-900:00:00.00", protocol_field_type::time, 0, 2); - output.emplace_back("gt_max", "900:00:00.00", protocol_field_type::time, 0, 2); - output.emplace_back("invalid_sign", "x670:00:00.00", protocol_field_type::time, 0, 2); - output.emplace_back("null_char", makesv("20:00:\00.00"), protocol_field_type::time, 0, 2); - output.emplace_back("trailing_0", "22:06:01k", protocol_field_type::time, 0, 0); - output.emplace_back("trailing_1", "22:06:01.1k", protocol_field_type::time, 0, 1); - output.emplace_back("trailing_2", "22:06:01.12k", protocol_field_type::time, 0, 2); - output.emplace_back("trailing_3", "22:06:01.123k", protocol_field_type::time, 0, 3); - output.emplace_back("trailing_4", "22:06:01.1234k", protocol_field_type::time, 0, 4); - output.emplace_back("trailing_5", "22:06:01.12345k", protocol_field_type::time, 0, 5); - output.emplace_back("trailing_6", "22:06:01.123456k", protocol_field_type::time, 0, 6); - output.emplace_back("double_sign", "--22:06:01.123456", protocol_field_type::time, 0, 6); -} - -std::vector make_all_samples() -{ - std::vector res; - add_int_samples(protocol_field_type::tiny, res); - add_int_samples(protocol_field_type::short_, res); - add_int_samples(protocol_field_type::int24, res); - add_int_samples(protocol_field_type::long_, res); - add_int_samples(protocol_field_type::longlong, res); - add_int_samples(protocol_field_type::year, res); - add_bit_samples(res); - add_float_samples(protocol_field_type::float_, "-2e90", "2e90", res); - add_float_samples(protocol_field_type::double_, "-2e9999", "2e9999", res); - add_date_samples(res); - add_datetime_samples(protocol_field_type::datetime, res); - add_datetime_samples(protocol_field_type::timestamp, res); - add_time_samples(res); - return res; -} - -BOOST_DATA_TEST_CASE(test_deserialize_text_value_error, data::make(make_all_samples())) -{ - column_definition_packet coldef {}; - coldef.type = sample.type; - coldef.decimals = static_cast(sample.decimals); - coldef.flags = sample.flags; - boost::mysql::metadata meta (coldef); - field_view actual_value; - auto err = deserialize_text_value(sample.from, meta, actual_value); - auto expected = sample.expected_err; - BOOST_TEST(expected == err); -} - -} // anon namespace