diff --git a/TODO.txt b/TODO.txt index ee72af38..998b3ffb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,11 +1,3 @@ -Name change - Split serialization tests according to file structure - serialization_test_common - Should be in unit/ - Should not be header only - Should have things in namespace test, not detail - Split serialization tests into chunks following file structure - Try to make string_fixed just an array of chars instead of a value_holder Multiresultset Text protocol Binary protocol (stored procedures) diff --git a/include/boost/mysql/detail/protocol/impl/handshake_messages.ipp b/include/boost/mysql/detail/protocol/impl/handshake_messages.ipp index c39054fa..a7fa20f9 100644 --- a/include/boost/mysql/detail/protocol/impl/handshake_messages.ipp +++ b/include/boost/mysql/detail/protocol/impl/handshake_messages.ipp @@ -34,8 +34,8 @@ boost::mysql::detail::serialization_traits< // Compose capabilities auto capabilities_begin = reinterpret_cast(&output.capability_falgs.value); - memcpy(capabilities_begin, capability_flags_low.value.data(), 2); - memcpy(capabilities_begin + 2, capability_flags_high.value.data(), 2); + memcpy(capabilities_begin, capability_flags_low.data(), 2); + memcpy(capabilities_begin + 2, capability_flags_high.data(), 2); boost::endian::little_to_native_inplace(output.capability_falgs.value); // Check minimum server capabilities to deserialize this frame @@ -59,7 +59,7 @@ boost::mysql::detail::serialization_traits< // Compose auth_plugin_data memcpy( output.auth_plugin_data_buffer.data(), - auth_plugin_data_part_1.value.data(), + auth_plugin_data_part_1.data(), auth1_length ); output.auth_plugin_data.value = std::string_view( diff --git a/include/boost/mysql/detail/protocol/impl/serialization.hpp b/include/boost/mysql/detail/protocol/impl/serialization.hpp index 4073d4af..d1517fe7 100644 --- a/include/boost/mysql/detail/protocol/impl/serialization.hpp +++ b/include/boost/mysql/detail/protocol/impl/serialization.hpp @@ -204,7 +204,7 @@ boost::mysql::errc boost::mysql::detail::serialization_traits< { return errc::incomplete_message; } - memcpy(&output.value, ctx.first(), N); + memcpy(output.data(), ctx.first(), N); ctx.advance(N); return errc::ok; } diff --git a/include/boost/mysql/detail/protocol/protocol_types.hpp b/include/boost/mysql/detail/protocol/protocol_types.hpp index 990a573c..002216e5 100644 --- a/include/boost/mysql/detail/protocol/protocol_types.hpp +++ b/include/boost/mysql/detail/protocol/protocol_types.hpp @@ -25,14 +25,7 @@ struct int8_signed : value_holder { using value_holder::value_hold struct int_lenenc : value_holder { using value_holder::value_holder; }; template -struct string_fixed : value_holder> -{ - constexpr string_fixed() = default; - explicit string_fixed(const char (&v) [size]) - { - std::memcpy(this->value.data(), v, size); - } -}; +using string_fixed = std::array; struct string_null : value_holder { using value_holder::value_holder; }; struct string_eof : value_holder { using value_holder::value_holder; }; diff --git a/include/boost/mysql/detail/protocol/serialization.hpp b/include/boost/mysql/detail/protocol/serialization.hpp index 5b68d8f2..3bb6e077 100644 --- a/include/boost/mysql/detail/protocol/serialization.hpp +++ b/include/boost/mysql/detail/protocol/serialization.hpp @@ -77,7 +77,7 @@ struct serialization_traits, serialization_tag::none> static errc deserialize_(string_fixed& output, deserialization_context& ctx) noexcept; static void serialize_(const string_fixed& input, serialization_context& ctx) noexcept { - ctx.write(input.value.data(), N); + ctx.write(input.data(), N); } static constexpr std::size_t get_size_(const string_fixed&, const serialization_context&) noexcept { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3b451511..10b2595a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,12 @@ endif() add_executable( mysql_unittests unit/detail/auth/mysql_native_password.cpp + unit/detail/protocol/serialization_test_common.cpp unit/detail/protocol/serialization.cpp + unit/detail/protocol/common_messages.cpp + unit/detail/protocol/handshake_messages.cpp + unit/detail/protocol/query_messages.cpp + unit/detail/protocol/prepared_statement_messages.cpp unit/detail/protocol/capabilities.cpp unit/detail/protocol/text_deserialization.cpp unit/detail/protocol/binary_deserialization.cpp diff --git a/test/common/serialization_test_common.hpp b/test/common/serialization_test_common.hpp deleted file mode 100644 index 2da4a68d..00000000 --- a/test/common/serialization_test_common.hpp +++ /dev/null @@ -1,316 +0,0 @@ -#ifndef TEST_SERIALIZATION_TEST_COMMON_HPP_ -#define TEST_SERIALIZATION_TEST_COMMON_HPP_ - -#include "boost/mysql/detail/protocol/serialization.hpp" -#include "boost/mysql/detail/protocol/constants.hpp" -#include "boost/mysql/value.hpp" -#include -#include -#include -#include -#include "test_common.hpp" - -namespace boost { -namespace mysql { -namespace detail { - -// Operator << for some basic types -template -std::ostream& operator<<(std::ostream& os, const std::array& v) -{ - return os << v.data(); -} - -inline std::ostream& operator<<(std::ostream& os, std::uint8_t value) -{ - return os << +value; -} - -using ::date::operator<<; - -// Operator == for structs -template -bool equals_struct(const T& lhs, const T& rhs) -{ - constexpr auto fields = get_struct_fields::value; - if constexpr (index == std::tuple_size::value) - { - return true; - } - else - { - constexpr auto pmem = std::get(fields); - return (rhs.*pmem == lhs.*pmem) && equals_struct(lhs, rhs); - } -} - -template -std::enable_if_t(), bool> -operator==(const T& lhs, const T& rhs) -{ - return equals_struct<0>(lhs, rhs); -} - -// Operator << for ValueHolder's -template -std::ostream& operator<<(std::ostream& os, const value_holder& value) -{ - return os << value.value; -} - -template -std::enable_if_t, std::ostream&> -operator<<(std::ostream& os, T value) -{ - return os << boost::typeindex::type_id().pretty_name() << "(" << - static_cast>(value) << ")"; -} - -// Operator << for structs -template -void print_struct(std::ostream& os, const T& value) -{ - constexpr auto fields = get_struct_fields::value; - if constexpr (index < std::tuple_size::value) - { - constexpr auto pmem = std::get(fields); - os << " " << (value.*pmem) << ",\n"; - print_struct(os, value); - } -} - -template -std::enable_if_t(), std::ostream&> -operator<<(std::ostream& os, const T& value) -{ - os << boost::typeindex::type_id().pretty_name() << "(\n"; - print_struct<0>(os, value); - os << ")\n"; - return os; -} - -class TypeErasedValue -{ -public: - virtual ~TypeErasedValue() {} - virtual void serialize(serialization_context& ctx) const = 0; - virtual std::size_t get_size(const serialization_context& ctx) const = 0; - virtual errc deserialize(deserialization_context& ctx) = 0; - virtual std::shared_ptr default_construct() const = 0; - virtual bool equals(const TypeErasedValue& rhs) const = 0; - virtual void print(std::ostream& os) const = 0; - - bool operator==(const TypeErasedValue& rhs) const { return equals(rhs); } -}; -inline std::ostream& operator<<(std::ostream& os, const TypeErasedValue& value) -{ - value.print(os); - return os; -} - -template -class TypeErasedValueImpl : public TypeErasedValue -{ - T value_; -public: - TypeErasedValueImpl(const T& v): value_(v) {}; - void serialize(serialization_context& ctx) const override { ::boost::mysql::detail::serialize(value_, ctx); } - std::size_t get_size(const serialization_context& ctx) const override { return ::boost::mysql::detail::get_size(value_, ctx); } - errc deserialize(deserialization_context& ctx) override { return ::boost::mysql::detail::deserialize(value_, ctx); } - std::shared_ptr default_construct() const override - { - return std::make_shared>(T{}); - } - bool equals(const TypeErasedValue& rhs) const override - { - auto typed_value = dynamic_cast*>(&rhs); - return typed_value && (typed_value->value_ == value_); - } - void print(std::ostream& os) const override - { - os << value_; - } -}; - -struct SerializeParams : test::named_param -{ - std::shared_ptr value; - std::vector expected_buffer; - std::string name; - capabilities caps; - std::any additional_storage; - - template - SerializeParams(const T& v, std::vector&& buff, - std::string&& name, std::uint32_t caps=0, std::any storage = {}): - value(std::make_shared>(v)), - expected_buffer(move(buff)), - name(move(name)), - caps(caps), - additional_storage(std::move(storage)) - { - } -}; - -std::vector concat(std::vector&& lhs, const std::vector& rhs) -{ - size_t lhs_size = lhs.size(); - std::vector res (move(lhs)); - res.resize(lhs_size + rhs.size()); - std::memcpy(res.data() + lhs_size, rhs.data(), rhs.size()); - return res; -} - -// Test fixtures -struct SerializationFixture : public testing::TestWithParam -{ - // get_size - void get_size_test() - { - serialization_context ctx (GetParam().caps, nullptr); - auto size = GetParam().value->get_size(ctx); - EXPECT_EQ(size, GetParam().expected_buffer.size()); - } - - // serialize - void serialize_test() - { - auto expected_size = GetParam().expected_buffer.size(); - std::vector buffer (expected_size + 8, 0x7a); // buffer overrun detector - serialization_context ctx (GetParam().caps, buffer.data()); - GetParam().value->serialize(ctx); - - // Iterator - EXPECT_EQ(ctx.first(), buffer.data() + expected_size) << "Iterator not updated correctly"; - - // Buffer - std::string_view expected_populated = test::makesv(GetParam().expected_buffer.data(), expected_size); - std::string_view actual_populated = test::makesv(buffer.data(), expected_size); - test::compare_buffers(expected_populated, actual_populated, "Buffer contents incorrect"); - - // Check for buffer overruns - std::string expected_clean (8, 0x7a); - std::string_view actual_clean = test::makesv(buffer.data() + expected_size, 8); - test::compare_buffers(expected_clean, actual_clean, "Buffer overrun"); - } - - // deserialize - void deserialize_test() - { - auto first = GetParam().expected_buffer.data(); - auto size = GetParam().expected_buffer.size(); - deserialization_context ctx (first, first + size, GetParam().caps); - auto actual_value = GetParam().value->default_construct(); - auto err = actual_value->deserialize(ctx); - - // No error - EXPECT_EQ(err, errc::ok); - - // Iterator advanced - EXPECT_EQ(ctx.first(), first + size); - - // Actual value - EXPECT_EQ(*actual_value, *GetParam().value); - } - - void deserialize_extra_space_test() - { - std::vector buffer (GetParam().expected_buffer); - buffer.push_back(0xff); - auto first = buffer.data(); - deserialization_context ctx (first, first + buffer.size(), GetParam().caps); - auto actual_value = GetParam().value->default_construct(); - auto err = actual_value->deserialize(ctx); - - // No error - EXPECT_EQ(err, errc::ok); - - // Iterator advanced - EXPECT_EQ(ctx.first(), first + GetParam().expected_buffer.size()); - - // Actual value - EXPECT_EQ(*actual_value, *GetParam().value); - } - - void deserialize_not_enough_space_test() - { - std::vector buffer (GetParam().expected_buffer); - buffer.back() = 0x7a; // try to detect any overruns - deserialization_context ctx (buffer.data(), buffer.data() + buffer.size() - 1, GetParam().caps); - auto actual_value = GetParam().value->default_construct(); - auto err = actual_value->deserialize(ctx); - EXPECT_EQ(err, errc::incomplete_message); - } -}; - -// Only serialization -struct SerializeTest : SerializationFixture {}; -TEST_P(SerializeTest, get_size) { get_size_test(); } -TEST_P(SerializeTest, serialize) { serialize_test(); } - -// Only deserialization -struct DeserializeTest : SerializationFixture {}; -TEST_P(DeserializeTest, deserialize) { deserialize_test(); } - -// Deserialization + extra/infra space -struct DeserializeSpaceTest : SerializationFixture {}; -TEST_P(DeserializeSpaceTest, deserialize) { deserialize_test(); } -TEST_P(DeserializeSpaceTest, deserialize_extra_space) { deserialize_extra_space_test(); } -TEST_P(DeserializeSpaceTest, deserialize_not_enough_space) { deserialize_not_enough_space_test(); } - -// Serialization + deserialization -struct SerializeDeserializeTest : SerializationFixture {}; -TEST_P(SerializeDeserializeTest, get_size) { get_size_test(); } -TEST_P(SerializeDeserializeTest, serialize) { serialize_test(); } -TEST_P(SerializeDeserializeTest, deserialize) { deserialize_test(); } - -// All -struct FullSerializationTest : SerializationFixture {}; -TEST_P(FullSerializationTest, get_size) { get_size_test(); } -TEST_P(FullSerializationTest, serialize) { serialize_test(); } -TEST_P(FullSerializationTest, deserialize) { deserialize_test(); } -TEST_P(FullSerializationTest, deserialize_extra_space) { deserialize_extra_space_test(); } -TEST_P(FullSerializationTest, deserialize_not_enough_space) { deserialize_not_enough_space_test(); } - - -// errc tests -struct DeserializeErrorParams : test::named_param -{ - std::shared_ptr value; - std::vector buffer; - std::string name; - errc expected_error; - - template - DeserializeErrorParams( - std::vector&& buffer, - std::string&& test_name, - errc err = errc::incomplete_message - ) : - value(std::make_shared>(T{})), - buffer(std::move(buffer)), - name(std::move(test_name)), - expected_error(err) - { - } -}; - -struct DeserializeErrorTest : testing::TestWithParam {}; - -TEST_P(DeserializeErrorTest, Deserialize_ErrorCondition_ReturnsErrorCode) -{ - auto first = GetParam().buffer.data(); - auto last = GetParam().buffer.data() + GetParam().buffer.size(); - deserialization_context ctx (first, last, capabilities(0)); - auto value = GetParam().value->default_construct(); - auto err = value->deserialize(ctx); - EXPECT_EQ(err, GetParam().expected_error); -} - - -} // detail -} // mysql -} // boost - - -#endif /* TEST_SERIALIZATION_TEST_COMMON_HPP_ */ diff --git a/test/common/test_common.hpp b/test/common/test_common.hpp index 735c6b1d..58d49910 100644 --- a/test/common/test_common.hpp +++ b/test/common/test_common.hpp @@ -4,6 +4,7 @@ #include "boost/mysql/value.hpp" #include "boost/mysql/row.hpp" #include "boost/mysql/error.hpp" +#include #include #include #include @@ -118,6 +119,27 @@ inline void compare_buffers(std::string_view s0, std::string_view s1, const char EXPECT_EQ(s0, s1) << msg << ":\n" << buffer_diff(s0, s1); } +inline void concat(std::vector& lhs, boost::asio::const_buffer rhs) +{ + auto current_size = lhs.size(); + lhs.resize(current_size + rhs.size()); + memcpy(lhs.data() + current_size, rhs.data(), rhs.size()); +} + +inline void concat(std::vector& lhs, const std::vector& rhs) +{ + concat(lhs, boost::asio::buffer(rhs)); +} + +inline std::vector concat_copy( + std::vector&& lhs, + const std::vector& rhs +) +{ + concat(lhs, rhs); + return std::move(lhs); +} + struct named_param {}; template >> diff --git a/test/unit/detail/protocol/channel.cpp b/test/unit/detail/protocol/channel.cpp index 2b1054d0..1d50b993 100644 --- a/test/unit/detail/protocol/channel.cpp +++ b/test/unit/detail/protocol/channel.cpp @@ -11,28 +11,18 @@ #include #include #include "boost/mysql/detail/protocol/channel.hpp" +#include "test_common.hpp" using namespace testing; using namespace boost::mysql::detail; using namespace boost::asio; using boost::mysql::error_code; using boost::mysql::errc; +using boost::mysql::test::concat; namespace { -void concat(std::vector& lhs, boost::asio::const_buffer rhs) -{ - auto current_size = lhs.size(); - lhs.resize(current_size + rhs.size()); - memcpy(lhs.data() + current_size, rhs.data(), rhs.size()); -} - -void concat(std::vector& lhs, const std::vector& rhs) -{ - concat(lhs, boost::asio::buffer(rhs)); -} - class MockStream { public: diff --git a/test/unit/detail/protocol/common_messages.cpp b/test/unit/detail/protocol/common_messages.cpp new file mode 100644 index 00000000..5f2a4c46 --- /dev/null +++ b/test/unit/detail/protocol/common_messages.cpp @@ -0,0 +1,176 @@ + +#include "serialization_test_common.hpp" +#include "boost/mysql/detail/protocol/common_messages.hpp" + +using namespace boost::mysql::test; +using namespace boost::mysql::detail; +using boost::mysql::collation; + +namespace +{ + +INSTANTIATE_TEST_SUITE_P(PacketHeader, FullSerializationTest, ::testing::Values( + serialization_testcase(packet_header{int3(3), int1(0)}, {0x03, 0x00, 0x00, 0x00}, "small_packet_seqnum_0"), + serialization_testcase(packet_header{int3(9), int1(2)}, {0x09, 0x00, 0x00, 0x02}, "small_packet_seqnum_not_0"), + serialization_testcase(packet_header{int3(0xcacbcc), int1(0xfa)}, {0xcc, 0xcb, 0xca, 0xfa}, "big_packet_seqnum_0"), + serialization_testcase(packet_header{int3(0xffffff), int1(0xff)}, {0xff, 0xff, 0xff, 0xff}, "max_packet_max_seqnum") +), test_name_generator); + +INSTANTIATE_TEST_SUITE_P(OkPacket, DeserializeTest, ::testing::Values( + serialization_testcase(ok_packet{ + int_lenenc(4), // affected rows + int_lenenc(0), // last insert ID + int2(SERVER_STATUS_AUTOCOMMIT | SERVER_QUERY_NO_INDEX_USED), // server status + int2(0), // warnings + string_lenenc("Rows matched: 5 Changed: 4 Warnings: 0") + }, { + 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x52, 0x6f, 0x77, 0x73, + 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x3a, 0x20, 0x35, 0x20, 0x20, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x3a, 0x20, 0x34, 0x20, 0x20, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, + 0x73, 0x3a, 0x20, 0x30 + }, "successful_update"), + + serialization_testcase(ok_packet{ + int_lenenc(1), // affected rows + int_lenenc(6), // last insert ID + int2(SERVER_STATUS_AUTOCOMMIT), // server status + int2(0), // warnings + string_lenenc("") // no message + },{ + 0x01, 0x06, 0x02, 0x00, 0x00, 0x00 + }, "successful_insert"), + + serialization_testcase(ok_packet{ + int_lenenc(0), // affected rows + int_lenenc(0), // last insert ID + int2(SERVER_STATUS_AUTOCOMMIT), // server status + int2(0), // warnings + string_lenenc("") // no message + }, { + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 + }, "successful_login") +), test_name_generator); + +INSTANTIATE_TEST_SUITE_P(ErrPacket, DeserializeTest, ::testing::Values( + serialization_testcase(err_packet{ + int2(1049), // eror code + string_fixed<1>{0x23}, // sql state marker + string_fixed<5>{'4', '2', '0', '0', '0'}, // sql state + string_eof("Unknown database 'a'") // err msg + }, { + 0x19, 0x04, 0x23, 0x34, 0x32, 0x30, 0x30, 0x30, 0x55, 0x6e, 0x6b, + 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x27, 0x61, 0x27 + }, "wrong_use_database"), + + serialization_testcase(err_packet{ + int2(1146), // eror code + string_fixed<1>{0x23}, // sql state marker + string_fixed<5>{'4', '2', 'S', '0', '2'}, // sql state + string_eof("Table 'awesome.unknown' doesn't exist") // err msg + }, { + 0x7a, 0x04, 0x23, 0x34, 0x32, 0x53, 0x30, 0x32, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x27, 0x61, + 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x2e, 0x75, + 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x27, 0x20, + 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, + 0x65, 0x78, 0x69, 0x73, 0x74 + }, "unknown_table"), + + serialization_testcase(err_packet{ + int2(1045), // error code + string_fixed<1>{0x23}, // SQL state marker + string_fixed<5>{'2', '8', '0', '0', '0'}, // SQL state + string_eof("Access denied for user 'root'@'localhost' (using password: YES)") + }, { + 0x15, 0x04, 0x23, 0x32, 0x38, 0x30, 0x30, 0x30, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x64, + 0x65, 0x6e, 0x69, 0x65, 0x64, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x27, + 0x72, 0x6f, 0x6f, 0x74, 0x27, 0x40, 0x27, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, + 0x27, 0x20, 0x28, 0x75, 0x73, 0x69, 0x6e, 0x67, + 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x3a, 0x20, 0x59, 0x45, 0x53, 0x29 + }, "failed_login") +), test_name_generator); + +// Column definition +INSTANTIATE_TEST_SUITE_P(ColumnDefinition, DeserializeSpaceTest, testing::Values( + serialization_testcase(column_definition_packet{ + string_lenenc("def"), //catalog + string_lenenc("awesome"), // schema (database) + string_lenenc("test_table"), // table + string_lenenc("test_table"), // physical table + string_lenenc("id"), // field name + string_lenenc("id"), // physical field name + collation::binary, + int4(11), // length + protocol_field_type::long_, + int2( + column_flags::not_null | + column_flags::pri_key | + column_flags::auto_increment | + column_flags::part_key + ), + int1(0) // decimals + }, { + 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, + 0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, + 0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x02, 0x69, 0x64, 0x02, 0x69, 0x64, + 0x0c, 0x3f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, + 0x03, 0x42, 0x00, 0x00, 0x00 + }, "numeric_auto_increment_primary_key"), + serialization_testcase(column_definition_packet{ + string_lenenc("def"), //catalog + string_lenenc("awesome"), // schema (database) + string_lenenc("child"), // table + string_lenenc("child_table"), // physical table + string_lenenc("field_alias"), // field name + string_lenenc("field_varchar"), // physical field name + collation::utf8_general_ci, + int4(765), // length + protocol_field_type::var_string, + int2(), // no column flags + int1(0) // decimals + }, { + 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, + 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, + 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0b, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, + 0x0c, 0x21, 0x00, 0xfd, 0x02, 0x00, 0x00, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00 + }, "varchar_field_aliased_field_and_table_names_join"), + + serialization_testcase(column_definition_packet{ + string_lenenc("def"), //catalog + string_lenenc("awesome"), // schema (database) + string_lenenc("test_table"), // table + string_lenenc("test_table"), // physical table + string_lenenc("field_float"), // field name + string_lenenc("field_float"), // physical field name + collation::binary, // binary + int4(12), // length + protocol_field_type::float_, + int2(), // no column flags + int1(31) // decimals + }, { + 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, + 0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, + 0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f, + 0x61, 0x74, 0x0c, 0x3f, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x00 + }, "float_field") +), test_name_generator); + + +} // anon namespace diff --git a/test/unit/detail/protocol/handshake_messages.cpp b/test/unit/detail/protocol/handshake_messages.cpp new file mode 100644 index 00000000..d27864b8 --- /dev/null +++ b/test/unit/detail/protocol/handshake_messages.cpp @@ -0,0 +1,177 @@ + +#include "serialization_test_common.hpp" +#include "boost/mysql/detail/protocol/handshake_messages.hpp" + +using namespace boost::mysql::test; +using namespace boost::mysql::detail; +using boost::mysql::collation; + +namespace +{ + +constexpr std::uint8_t handshake_auth_plugin_data [] = { + 0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f, + 0x03, 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, + 0x43, 0x4a, 0x21, 0x62 +}; + +constexpr std::uint32_t hanshake_caps = + CLIENT_LONG_PASSWORD | + CLIENT_FOUND_ROWS | + CLIENT_LONG_FLAG | + CLIENT_CONNECT_WITH_DB | + CLIENT_NO_SCHEMA | + CLIENT_COMPRESS | + CLIENT_ODBC | + CLIENT_LOCAL_FILES | + CLIENT_IGNORE_SPACE | + CLIENT_PROTOCOL_41 | + CLIENT_INTERACTIVE | + CLIENT_IGNORE_SIGPIPE | + CLIENT_TRANSACTIONS | + CLIENT_RESERVED | // old flag, but set in this frame + CLIENT_SECURE_CONNECTION | // old flag, but set in this frame + CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS | + CLIENT_PS_MULTI_RESULTS | + CLIENT_PLUGIN_AUTH | + CLIENT_CONNECT_ATTRS | + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | + CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS | + CLIENT_SESSION_TRACK | + CLIENT_DEPRECATE_EOF | + CLIENT_REMEMBER_OPTIONS; + +INSTANTIATE_TEST_SUITE_P(Handhsake, DeserializeSpaceTest, ::testing::Values( + serialization_testcase(handshake_packet{ + string_null("5.7.27-0ubuntu0.19.04.1"), // server version + int4(2), // connection ID + string_lenenc(makesv(handshake_auth_plugin_data)), + int4(hanshake_caps), + int1(static_cast(collation::latin1_swedish_ci)), + int2(SERVER_STATUS_AUTOCOMMIT), + string_null("mysql_native_password"), + {} // data buffer; internal, not used in the comparisons for correctness + }, { + 0x35, 0x2e, 0x37, 0x2e, 0x32, 0x37, 0x2d, 0x30, + 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x2e, + 0x31, 0x39, 0x2e, 0x30, 0x34, 0x2e, 0x31, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x52, 0x1a, 0x50, 0x3a, + 0x4b, 0x12, 0x70, 0x2f, 0x00, 0xff, 0xf7, 0x08, + 0x02, 0x00, 0xff, 0x81, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, + 0x4a, 0x21, 0x62, 0x00, 0x6d, 0x79, 0x73, 0x71, + 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x00 + }, "regular") +), test_name_generator); + +constexpr std::uint8_t handshake_response_auth_data [] = { + 0xfe, 0xc6, 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, + 0xc5, 0x51, 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, + 0xe6, 0xfc, 0x34, 0xc9 +}; + +constexpr std::uint32_t handshake_response_caps = + CLIENT_LONG_PASSWORD | + CLIENT_LONG_FLAG | + CLIENT_LOCAL_FILES | + CLIENT_PROTOCOL_41 | + CLIENT_INTERACTIVE | + CLIENT_TRANSACTIONS | + CLIENT_SECURE_CONNECTION | + CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS | + CLIENT_PS_MULTI_RESULTS | + CLIENT_PLUGIN_AUTH | + CLIENT_CONNECT_ATTRS | + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | + CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS | + CLIENT_SESSION_TRACK | + CLIENT_DEPRECATE_EOF; + +INSTANTIATE_TEST_SUITE_P(HandhsakeResponse, SerializeTest, ::testing::Values( + serialization_testcase(handshake_response_packet{ + int4(handshake_response_caps), + int4(16777216), // max packet size + int1(static_cast(collation::utf8_general_ci)), + string_null("root"), + string_lenenc(makesv(handshake_response_auth_data)), + string_null(""), // Irrelevant, not using connect with DB + string_null("mysql_native_password") // auth plugin name + }, { + 0x85, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, + 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51, + 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, + 0x34, 0xc9, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00 + }, "without_database", handshake_response_caps), + + serialization_testcase(handshake_response_packet{ + int4(handshake_response_caps | CLIENT_CONNECT_WITH_DB), + int4(16777216), // max packet size + int1(static_cast(collation::utf8_general_ci)), + string_null("root"), + string_lenenc(makesv(handshake_response_auth_data)), + string_null("database"), // database name + string_null("mysql_native_password") // auth plugin name + }, { + 0x8d, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, + 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51, + 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, + 0x34, 0xc9, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, + 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x00 + }, "with_database", handshake_response_caps | CLIENT_CONNECT_WITH_DB) +), test_name_generator); + +constexpr std::uint8_t auth_switch_request_auth_data [] = { + 0x49, 0x49, 0x7e, 0x51, 0x5d, 0x1f, 0x19, 0x6a, + 0x0f, 0x5a, 0x63, 0x15, 0x3e, 0x28, 0x31, 0x3e, + 0x3c, 0x79, 0x09, 0x7c +}; + +INSTANTIATE_TEST_SUITE_P(AuthSwitchRequest, DeserializeTest, testing::Values( + serialization_testcase(auth_switch_request_packet{ + string_null("mysql_native_password"), + string_eof(makesv(auth_switch_request_auth_data)) + }, { + 0x6d, 0x79, 0x73, + 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x00, 0x49, 0x49, 0x7e, 0x51, 0x5d, + 0x1f, 0x19, 0x6a, 0x0f, 0x5a, 0x63, 0x15, 0x3e, + 0x28, 0x31, 0x3e, 0x3c, 0x79, 0x09, 0x7c, 0x00 + }, "regular") +), test_name_generator); + +constexpr std::uint8_t auth_switch_response_auth_data [] = { + 0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, + 0x91, 0xff, 0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, + 0x88, 0x2d, 0xf9, 0xcf +}; + +INSTANTIATE_TEST_SUITE_P(AuthSwitchResponse, SerializeTest, testing::Values( + serialization_testcase(auth_switch_response_packet{ + string_eof(makesv(auth_switch_response_auth_data)) + }, { + 0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, + 0x91, 0xff, 0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, + 0x88, 0x2d, 0xf9, 0xcf + }, "regular") +), test_name_generator); + +} // anon namespace diff --git a/test/unit/detail/protocol/prepared_statement_messages.cpp b/test/unit/detail/protocol/prepared_statement_messages.cpp new file mode 100644 index 00000000..45a1ef29 --- /dev/null +++ b/test/unit/detail/protocol/prepared_statement_messages.cpp @@ -0,0 +1,201 @@ + +#include "serialization_test_common.hpp" +#include "boost/mysql/detail/protocol/prepared_statement_messages.hpp" +#include +#include + +using namespace boost::mysql::test; +using namespace boost::mysql::detail; +using boost::mysql::value; + +namespace +{ + +INSTANTIATE_TEST_SUITE_P(ComStmtPrepare, SerializeTest, testing::Values( + serialization_testcase(com_stmt_prepare_packet{ + string_eof("SELECT * from three_rows_table WHERE id = ?") + }, { + 0x16, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, + 0x2a, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, + 0x68, 0x72, 0x65, 0x65, 0x5f, 0x72, 0x6f, 0x77, + 0x73, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x57, 0x48, 0x45, 0x52, 0x45, 0x20, 0x69, 0x64, + 0x20, 0x3d, 0x20, 0x3f + }, "regular") +), test_name_generator); + +INSTANTIATE_TEST_SUITE_P(ComStmtPrepareResponse, DeserializeSpaceTest, testing::Values( + serialization_testcase(com_stmt_prepare_ok_packet{ + int4(1), // statement id + int2(2), // number of fields + int2(3), // number of params + int2(0), // warnings + }, { + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00 + }, "regular") +), test_name_generator); + +// Helper for composing ComStmtExecute tests +template > +serialization_testcase make_stmt_execute_test( + std::uint32_t stmt_id, + std::uint8_t flags, + std::uint32_t itercount, + std::uint8_t new_params_flag, + std::vector&& params, + std::vector&& buffer, + std::string&& test_name +) +{ + auto params_shared = std::make_shared(std::begin(params), std::end(params)); + return serialization_testcase( + com_stmt_execute_packet { + int4(stmt_id), + int1(flags), + int4(itercount), + int1(new_params_flag), + params_shared->begin(), + params_shared->end() + }, + std::move(buffer), + std::move(test_name), + 0, // capabilities + params_shared + ); +} + +INSTANTIATE_TEST_SUITE_P(ComStmtExecute, SerializeTest, testing::Values( + make_stmt_execute_test(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params + { std::uint32_t(0xabffff) }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x03, 0x80, 0xff, 0xff, + 0xab, 0x00 + }, + "uint32_t" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { std::int32_t(-0xabffff) }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x54, 0xff + }, + "int32_t" + ), + make_stmt_execute_test(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params + { 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 + }, + "uint64_t" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { 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 + }, + "int64_t" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { std::string_view("test") }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x04, 0x74, + 0x65, 0x73, 0x74 + }, + "string_view" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { 3.14e20f }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x2d, + 0x88, 0x61 + }, + "float" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { 2.1e214 }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x56, 0xc0, + 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c + }, + "double" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { makedate(2010, 9, 3) }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x04, 0xda, + 0x07, 0x09, 0x03 + }, + "date" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { 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, + 0x03, 0x00 + }, + "datetime" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { 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, + 0x89, 0x03, 0x00 + }, + "time" + ), + make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params + { nullptr }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x06, 0x00 + }, + "null" + ), + make_stmt_execute_test(2, 0, 1, 1, makevalues( + std::uint32_t(0xabffff), + std::int32_t(-0xabffff), + std::uint64_t(0xabffffabacadae), + std::int64_t(-0xabffffabacadae), + std::string_view("test"), + nullptr, + 2.1e214, + makedate(2010, 9, 3), + makedt(2010, 9, 3, 10, 30, 59, 231800), + maket(230, 30, 59, 231800), + nullptr + ), { + 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x20, 0x04, 0x01, 0x03, 0x80, 0x03, + 0x00, 0x08, 0x80, 0x08, 0x00, 0x0f, 0x00, 0x06, + 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0b, + 0x00, 0x06, 0x00, 0xff, 0xff, 0xab, 0x00, 0x01, + 0x00, 0x54, 0xff, 0xae, 0xad, 0xac, 0xab, 0xff, + 0xff, 0xab, 0x00, 0x52, 0x52, 0x53, 0x54, 0x00, + 0x00, 0x54, 0xff, 0x04, 0x74, 0x65, 0x73, 0x74, + 0x56, 0xc0, 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c, + 0x04, 0xda, 0x07, 0x09, 0x03, 0x0b, 0xda, 0x07, + 0x09, 0x03, 0x0a, 0x1e, 0x3b, 0x78, 0x89, 0x03, + 0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, + 0x1e, 0x3b, 0x78, 0x89, 0x03, 0x00 + }, + "several_params" + ), + make_stmt_execute_test>(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params + { std::uint32_t(0xabffff) }, { + 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x03, 0x80, 0xff, 0xff, + 0xab, 0x00 + }, + "forward_list_iterator" + ) +), test_name_generator); + +INSTANTIATE_TEST_SUITE_P(ComStmtClose, SerializeTest, testing::Values( + serialization_testcase(com_stmt_close_packet{int4(1)}, {0x19, 0x01, 0x00, 0x00, 0x00}, "regular") +), test_name_generator); + +} diff --git a/test/unit/detail/protocol/query_messages.cpp b/test/unit/detail/protocol/query_messages.cpp new file mode 100644 index 00000000..8b7901ed --- /dev/null +++ b/test/unit/detail/protocol/query_messages.cpp @@ -0,0 +1,20 @@ + +#include "serialization_test_common.hpp" +#include "boost/mysql/detail/protocol/query_messages.hpp" + +using namespace boost::mysql::test; +using namespace boost::mysql::detail; + +namespace +{ + +INSTANTIATE_TEST_SUITE_P(ComQuery, SerializeTest, testing::Values( + serialization_testcase(com_query_packet{ + string_eof("show databases") + }, { + 0x03, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73 + }, "regular") +), test_name_generator); + +} diff --git a/test/unit/detail/protocol/serialization.cpp b/test/unit/detail/protocol/serialization.cpp index 72caa339..138ed59c 100644 --- a/test/unit/detail/protocol/serialization.cpp +++ b/test/unit/detail/protocol/serialization.cpp @@ -6,16 +6,8 @@ */ #include "serialization_test_common.hpp" -#include "boost/mysql/detail/protocol/common_messages.hpp" -#include "boost/mysql/detail/protocol/handshake_messages.hpp" -#include "boost/mysql/detail/protocol/query_messages.hpp" -#include "boost/mysql/detail/protocol/prepared_statement_messages.hpp" #include "test_common.hpp" -#include -#include -using namespace testing; -using namespace std; using namespace boost::mysql::detail; using namespace boost::mysql::test; using boost::mysql::errc; @@ -25,13 +17,11 @@ using boost::mysql::value; namespace { - - // Definitions for the parameterized tests -string string_250 (250, 'a'); -string string_251 (251, 'a'); -string string_ffff (0xffff, 'a'); -string string_10000 (0x10000, 'a'); +std::string string_250 (250, 'a'); +std::string string_251 (251, 'a'); +std::string string_ffff (0xffff, 'a'); +std::string string_10000 (0x10000, 'a'); enum class EnumInt1 : uint8_t { @@ -55,675 +45,171 @@ enum class EnumInt4 : uint32_t }; INSTANTIATE_TEST_SUITE_P(UnsignedFixedSizeInts, FullSerializationTest, ::testing::Values( - SerializeParams(int1(0xff), {0xff}, "int1"), - SerializeParams(int2(0xfeff), {0xff, 0xfe}, "int2"), - SerializeParams(int3(0xfdfeff), {0xff, 0xfe, 0xfd}, "int3"), - SerializeParams(int4(0xfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc}, "int4"), - SerializeParams(int6(0xfafbfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa}, "int6"), - SerializeParams(int8(0xf8f9fafbfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, "int8") + serialization_testcase(int1(0xff), {0xff}, "int1"), + serialization_testcase(int2(0xfeff), {0xff, 0xfe}, "int2"), + serialization_testcase(int3(0xfdfeff), {0xff, 0xfe, 0xfd}, "int3"), + serialization_testcase(int4(0xfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc}, "int4"), + serialization_testcase(int6(0xfafbfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa}, "int6"), + serialization_testcase(int8(0xf8f9fafbfcfdfeff), {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, "int8") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(SignedFixedSizeInts, FullSerializationTest, ::testing::Values( - SerializeParams(int1_signed(-1), {0xff}, "int1_negative"), - SerializeParams(int2_signed(-0x101), {0xff, 0xfe}, "int2_negative"), - SerializeParams(int4_signed(-0x3020101), {0xff, 0xfe, 0xfd, 0xfc}, "int4_negative"), - SerializeParams(int8_signed(-0x0706050403020101), {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, "int8_negative"), - SerializeParams(int1_signed(0x01), {0x01}, "int1_positive"), - SerializeParams(int2_signed(0x0201), {0x01, 0x02}, "int2_positive"), - SerializeParams(int4_signed(0x04030201), {0x01, 0x02, 0x03, 0x04}, "int4_positive"), - SerializeParams(int8_signed(0x0807060504030201), {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, "int8_positive") + serialization_testcase(int1_signed(-1), {0xff}, "int1_negative"), + serialization_testcase(int2_signed(-0x101), {0xff, 0xfe}, "int2_negative"), + serialization_testcase(int4_signed(-0x3020101), {0xff, 0xfe, 0xfd, 0xfc}, "int4_negative"), + serialization_testcase(int8_signed(-0x0706050403020101), + {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, "int8_negative"), + serialization_testcase(int1_signed(0x01), {0x01}, "int1_positive"), + serialization_testcase(int2_signed(0x0201), {0x01, 0x02}, "int2_positive"), + serialization_testcase(int4_signed(0x04030201), {0x01, 0x02, 0x03, 0x04}, "int4_positive"), + serialization_testcase(int8_signed(0x0807060504030201), + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, "int8_positive") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(LengthEncodedInt, FullSerializationTest, ::testing::Values( - SerializeParams(int_lenenc(1), {0x01}, "1_byte_regular"), - SerializeParams(int_lenenc(250), {0xfa}, "1_byte_max"), - SerializeParams(int_lenenc(0xfeb7), {0xfc, 0xb7, 0xfe}, "2_bytes_regular"), - SerializeParams(int_lenenc(0xffff), {0xfc, 0xff, 0xff}, "2_bytes_max"), - SerializeParams(int_lenenc(0xa0feff), {0xfd, 0xff, 0xfe, 0xa0}, "3_bytes_regular"), - SerializeParams(int_lenenc(0xffffff), {0xfd, 0xff, 0xff, 0xff}, "3_bytes_max"), - SerializeParams(int_lenenc(0xf8f9fafbfcfdfeff), + serialization_testcase(int_lenenc(1), {0x01}, "1_byte_regular"), + serialization_testcase(int_lenenc(250), {0xfa}, "1_byte_max"), + serialization_testcase(int_lenenc(0xfeb7), {0xfc, 0xb7, 0xfe}, "2_bytes_regular"), + serialization_testcase(int_lenenc(0xffff), {0xfc, 0xff, 0xff}, "2_bytes_max"), + serialization_testcase(int_lenenc(0xa0feff), {0xfd, 0xff, 0xfe, 0xa0}, "3_bytes_regular"), + serialization_testcase(int_lenenc(0xffffff), {0xfd, 0xff, 0xff, 0xff}, "3_bytes_max"), + serialization_testcase(int_lenenc(0xf8f9fafbfcfdfeff), {0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, "8_bytes_regular"), - SerializeParams(int_lenenc(0xffffffffffffffff), + serialization_testcase(int_lenenc(0xffffffffffffffff), {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, "8_bytes_max") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(FixedSizeString, FullSerializationTest, ::testing::Values( - SerializeParams(string_fixed<4>({'a', 'b', 'd', 'e'}), {0x61, 0x62, 0x64, 0x65}, "4c_regular_characters"), - SerializeParams(string_fixed<3>({'\0', '\1', 'a'}), {0x00, 0x01, 0x61}, "3c_null_characters"), - SerializeParams(string_fixed<3>({char(0xc3), char(0xb1), 'a'}), {0xc3, 0xb1, 0x61}, "3c_utf8_characters"), - SerializeParams(string_fixed<1>({'a'}), {0x61}, "1c_regular_characters") + serialization_testcase(string_fixed<4>{'a', 'b', 'd', 'e'}, + {0x61, 0x62, 0x64, 0x65}, "4c_regular_characters"), + serialization_testcase(string_fixed<3>{'\0', '\1', 'a'}, + {0x00, 0x01, 0x61}, "3c_null_characters"), + serialization_testcase(string_fixed<3>{char(0xc3), char(0xb1), 'a'}, + {0xc3, 0xb1, 0x61}, "3c_utf8_characters"), + serialization_testcase(string_fixed<1>{'a'}, + {0x61}, "1c_regular_characters") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(NullTerminatedString, FullSerializationTest, ::testing::Values( - SerializeParams(string_null("abc"), {0x61, 0x62, 0x63, 0x00}, "regular_characters"), - SerializeParams(string_null("\xc3\xb1"), {0xc3, 0xb1, 0x00}, "utf8_characters"), - SerializeParams(string_null(""), {0x00}, "empty") + serialization_testcase(string_null("abc"), {0x61, 0x62, 0x63, 0x00}, "regular_characters"), + serialization_testcase(string_null("\xc3\xb1"), {0xc3, 0xb1, 0x00}, "utf8_characters"), + serialization_testcase(string_null(""), {0x00}, "empty") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(LengthEncodedString, FullSerializationTest, ::testing::Values( - SerializeParams(string_lenenc(""), {0x00}, "empty"), - SerializeParams(string_lenenc("abc"), {0x03, 0x61, 0x62, 0x63}, "1_byte_size_regular_characters"), - SerializeParams(string_lenenc(string_view("a\0b", 3)), {0x03, 0x61, 0x00, 0x62}, "1_byte_size_null_characters"), - SerializeParams(string_lenenc(string_250), concat({250}, vector(250, 0x61)), "1_byte_size_max"), - SerializeParams(string_lenenc(string_251), concat({0xfc, 251, 0}, vector(251, 0x61)), "2_byte_size_min"), - SerializeParams(string_lenenc(string_ffff), concat({0xfc, 0xff, 0xff}, vector(0xffff, 0x61)), "2_byte_size_max"), - SerializeParams(string_lenenc(string_10000), concat({0xfd, 0x00, 0x00, 0x01}, vector(0x10000, 0x61)), "3_byte_size_min") + serialization_testcase(string_lenenc(""), {0x00}, "empty"), + serialization_testcase(string_lenenc("abc"), + {0x03, 0x61, 0x62, 0x63}, "1_byte_size_regular_characters"), + serialization_testcase(string_lenenc(std::string_view("a\0b", 3)), + {0x03, 0x61, 0x00, 0x62}, "1_byte_size_null_characters"), + serialization_testcase(string_lenenc(string_250), + concat_copy({250}, std::vector(250, 0x61)), "1_byte_size_max"), + serialization_testcase(string_lenenc(string_251), + concat_copy({0xfc, 251, 0}, std::vector(251, 0x61)), "2_byte_size_min"), + serialization_testcase(string_lenenc(string_ffff), + concat_copy({0xfc, 0xff, 0xff}, std::vector(0xffff, 0x61)), "2_byte_size_max"), + serialization_testcase(string_lenenc(string_10000), + concat_copy({0xfd, 0x00, 0x00, 0x01}, std::vector(0x10000, 0x61)), "3_byte_size_min") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(EofString, SerializeDeserializeTest, ::testing::Values( - SerializeParams(string_eof("abc"), {0x61, 0x62, 0x63}, "regular_characters"), - SerializeParams(string_eof(string_view("a\0b", 3)), {0x61, 0x00, 0x62}, "null_characters"), - SerializeParams(string_eof(""), {}, "empty") + serialization_testcase(string_eof("abc"), {0x61, 0x62, 0x63}, "regular_characters"), + serialization_testcase(string_eof(std::string_view("a\0b", 3)), {0x61, 0x00, 0x62}, "null_characters"), + serialization_testcase(string_eof(""), {}, "empty") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(Enums, FullSerializationTest, ::testing::Values( - SerializeParams(EnumInt1::value1, {0x03}, "int1_low_value"), - SerializeParams(EnumInt1::value2, {0xff}, "int1_high_value"), - SerializeParams(EnumInt2::value1, {0x03, 0x00}, "int2_low_value"), - SerializeParams(EnumInt2::value2, {0xff, 0xfe}, "int2_high_value"), - SerializeParams(EnumInt4::value1, {0x03, 0x00, 0x00, 0x00}, "int4_low_value"), - SerializeParams(EnumInt4::value2, {0xff, 0xfe, 0xfd, 0xfc}, "int4_high_value") + serialization_testcase(EnumInt1::value1, {0x03}, "int1_low_value"), + serialization_testcase(EnumInt1::value2, {0xff}, "int1_high_value"), + serialization_testcase(EnumInt2::value1, {0x03, 0x00}, "int2_low_value"), + serialization_testcase(EnumInt2::value2, {0xff, 0xfe}, "int2_high_value"), + serialization_testcase(EnumInt4::value1, {0x03, 0x00, 0x00, 0x00}, "int4_low_value"), + serialization_testcase(EnumInt4::value2, {0xff, 0xfe, 0xfd, 0xfc}, "int4_high_value") ), test_name_generator); // Other binary values INSTANTIATE_TEST_SUITE_P(Float, FullSerializationTest, ::testing::Values( - SerializeParams(-4.2f, {0x66, 0x66, 0x86, 0xc0}, "fractional_negative"), - SerializeParams(4.2f, {0x66, 0x66, 0x86, 0x40}, "fractional_positive"), - SerializeParams(3.14e20f, {0x01, 0x2d, 0x88, 0x61}, "positive_exp_positive_fractional"), - SerializeParams(0.0f, {0x00, 0x00, 0x00, 0x00}, "zero") + serialization_testcase(-4.2f, {0x66, 0x66, 0x86, 0xc0}, "fractional_negative"), + serialization_testcase(4.2f, {0x66, 0x66, 0x86, 0x40}, "fractional_positive"), + serialization_testcase(3.14e20f, {0x01, 0x2d, 0x88, 0x61}, "positive_exp_positive_fractional"), + serialization_testcase(0.0f, {0x00, 0x00, 0x00, 0x00}, "zero") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(Double, FullSerializationTest, ::testing::Values( - SerializeParams(-4.2, {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}, "fractional_negative"), - SerializeParams(4.2, {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}, "fractional_positive"), - SerializeParams(3.14e200, {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69}, "positive_exp_positive_fractional"), - SerializeParams(0.0, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "zero") + serialization_testcase(-4.2, {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}, "fractional_negative"), + serialization_testcase(4.2, {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}, "fractional_positive"), + serialization_testcase(3.14e200, {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69}, "positive_exp_positive_fractional"), + serialization_testcase(0.0, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "zero") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(Date, FullSerializationTest, ::testing::Values( - SerializeParams(makedate(2010, 3, 28), {0x04, 0xda, 0x07, 0x03, 0x1c}, "regular"), - SerializeParams(makedate(1000, 1, 1), {0x04, 0xe8, 0x03, 0x01, 0x01}, "min"), - SerializeParams(makedate(9999, 12, 31), {0x04, 0x0f, 0x27, 0x0c, 0x1f}, "max") + serialization_testcase(makedate(2010, 3, 28), {0x04, 0xda, 0x07, 0x03, 0x1c}, "regular"), + serialization_testcase(makedate(1000, 1, 1), {0x04, 0xe8, 0x03, 0x01, 0x01}, "min"), + serialization_testcase(makedate(9999, 12, 31), {0x04, 0x0f, 0x27, 0x0c, 0x1f}, "max") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(Datetime, FullSerializationTest, ::testing::Values( - SerializeParams(makedt(2010, 1, 1), {0x04, 0xda, 0x07, 0x01, 0x01}, "only_date"), - SerializeParams(makedt(2010, 1, 1, 20, 0, 0, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x14, 0x00, 0x00}, "date_h"), - SerializeParams(makedt(2010, 1, 1, 0, 1, 0, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00}, "date_m"), - SerializeParams(makedt(2010, 1, 1, 3, 2, 0, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x03, 0x02, 0x00}, "date_hm"), - SerializeParams(makedt(2010, 1, 1, 0, 0, 1, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x01}, "date_s"), - SerializeParams(makedt(2010, 1, 1, 0, 59, 1, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x3b, 0x01}, "date_ms"), - SerializeParams(makedt(2010, 1, 1, 5, 0, 1, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x05, 0x00, 0x01}, "date_hs"), - SerializeParams(makedt(2010, 1, 1, 23, 1, 59, 0), {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b}, "date_hms"), - SerializeParams(makedt(2010, 1, 1, 0, 0, 0, 251000), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x78, 0xd4, 0x03, 0x00}, "date_u"), - SerializeParams(makedt(2010, 1, 1, 23, 0, 0, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x00, - 0x56, 0xc3, 0x0e, 0x00}, "date_hu"), - SerializeParams(makedt(2010, 1, 1, 0, 1, 0, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00, - 0x56, 0xc3, 0x0e, 0x00}, "date_mu"), - SerializeParams(makedt(2010, 1, 1, 23, 1, 0, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x00, - 0x56, 0xc3, 0x0e, 0x00}, "date_hmu"), - SerializeParams(makedt(2010, 1, 1, 0, 0, 59, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x3b, - 0x56, 0xc3, 0x0e, 0x00}, "date_su"), - SerializeParams(makedt(2010, 1, 1, 0, 1, 59, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x3b, - 0x56, 0xc3, 0x0e, 0x00}, "date_msu"), - SerializeParams(makedt(2010, 1, 1, 23, 0, 59, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x3b, - 0x56, 0xc3, 0x0e, 0x00}, "date_hsu"), - SerializeParams(makedt(2010, 1, 1, 23, 1, 59, 967510), {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, - 0x56, 0xc3, 0x0e, 0x00}, "date_hmsu") + serialization_testcase(makedt(2010, 1, 1), + {0x04, 0xda, 0x07, 0x01, 0x01}, "only_date"), + serialization_testcase(makedt(2010, 1, 1, 20, 0, 0, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x14, 0x00, 0x00}, "date_h"), + serialization_testcase(makedt(2010, 1, 1, 0, 1, 0, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00}, "date_m"), + serialization_testcase(makedt(2010, 1, 1, 3, 2, 0, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x03, 0x02, 0x00}, "date_hm"), + serialization_testcase(makedt(2010, 1, 1, 0, 0, 1, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x01}, "date_s"), + serialization_testcase(makedt(2010, 1, 1, 0, 59, 1, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x3b, 0x01}, "date_ms"), + serialization_testcase(makedt(2010, 1, 1, 5, 0, 1, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x05, 0x00, 0x01}, "date_hs"), + serialization_testcase(makedt(2010, 1, 1, 23, 1, 59, 0), + {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b}, "date_hms"), + serialization_testcase(makedt(2010, 1, 1, 0, 0, 0, 251000), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x78, 0xd4, 0x03, 0x00}, "date_u"), + serialization_testcase(makedt(2010, 1, 1, 23, 0, 0, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x00, 0x56, 0xc3, 0x0e, 0x00}, "date_hu"), + serialization_testcase(makedt(2010, 1, 1, 0, 1, 0, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00}, "date_mu"), + serialization_testcase(makedt(2010, 1, 1, 23, 1, 0, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00}, "date_hmu"), + serialization_testcase(makedt(2010, 1, 1, 0, 0, 59, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, "date_su"), + serialization_testcase(makedt(2010, 1, 1, 0, 1, 59, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, "date_msu"), + serialization_testcase(makedt(2010, 1, 1, 23, 0, 59, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, "date_hsu"), + serialization_testcase(makedt(2010, 1, 1, 23, 1, 59, 967510), + {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}, "date_hmsu") ), test_name_generator); INSTANTIATE_TEST_SUITE_P(Time, FullSerializationTest, ::testing::Values( - SerializeParams(maket(0, 0, 0), {0x00}, "zero"), - SerializeParams(maket(48, 0, 0, 0), {0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}, "positive_d"), - SerializeParams(maket(21, 0, 0, 0), {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, - 0x00}, "positive_h"), - SerializeParams(maket(0, 40, 0), {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x00}, "positive_m"), - SerializeParams(maket(0, 0, 21), {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15}, "positive_s"), - SerializeParams(maket(0, 0, 0, 321000), {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xe8, 0xe5, 0x04, 0x00}, "positive_u"), - SerializeParams(maket(838, 59, 58, 999000), {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, - 0x3a, 0x58, 0x3e, 0x0f, 0x00}, "positive_hmsu"), - SerializeParams(-maket(48, 0, 0, 0), {0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}, "negative_d"), - SerializeParams(-maket(21, 0, 0, 0), {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, - 0x00}, "negative_h"), - SerializeParams(-maket(0, 40, 0), {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x00}, "negative_m"), - SerializeParams(-maket(0, 0, 21), {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15}, "negative_s"), - SerializeParams(-maket(0, 0, 0, 321000), {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xe8, 0xe5, 0x04, 0x00}, "negative_u"), - SerializeParams(-maket(838, 59, 58, 999000), {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, - 0x3a, 0x58, 0x3e, 0x0f, 0x00}, "negative_hmsu") -), test_name_generator); - -// Messages -INSTANTIATE_TEST_SUITE_P(PacketHeader, FullSerializationTest, ::testing::Values( - SerializeParams(packet_header{int3(3), int1(0)}, {0x03, 0x00, 0x00, 0x00}, "small_packet_seqnum_0"), - SerializeParams(packet_header{int3(9), int1(2)}, {0x09, 0x00, 0x00, 0x02}, "small_packet_seqnum_not_0"), - SerializeParams(packet_header{int3(0xcacbcc), int1(0xfa)}, {0xcc, 0xcb, 0xca, 0xfa}, "big_packet_seqnum_0"), - SerializeParams(packet_header{int3(0xffffff), int1(0xff)}, {0xff, 0xff, 0xff, 0xff}, "max_packet_max_seqnum") -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(OkPacket, DeserializeTest, ::testing::Values( - SerializeParams(ok_packet{ - int_lenenc(4), // affected rows - int_lenenc(0), // last insert ID - int2(SERVER_STATUS_AUTOCOMMIT | SERVER_QUERY_NO_INDEX_USED), // server status - int2(0), // warnings - string_lenenc("Rows matched: 5 Changed: 4 Warnings: 0") - }, { - 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x52, 0x6f, 0x77, 0x73, - 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x3a, 0x20, 0x35, 0x20, 0x20, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x3a, 0x20, 0x34, 0x20, 0x20, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, - 0x73, 0x3a, 0x20, 0x30 - }, "successful_update"), - - SerializeParams(ok_packet{ - int_lenenc(1), // affected rows - int_lenenc(6), // last insert ID - int2(SERVER_STATUS_AUTOCOMMIT), // server status - int2(0), // warnings - string_lenenc("") // no message - },{ - 0x01, 0x06, 0x02, 0x00, 0x00, 0x00 - }, "successful_insert"), - - SerializeParams(ok_packet{ - int_lenenc(0), // affected rows - int_lenenc(0), // last insert ID - int2(SERVER_STATUS_AUTOCOMMIT), // server status - int2(0), // warnings - string_lenenc("") // no message - }, { - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 - }, "successful_login") -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(ErrPacket, DeserializeTest, ::testing::Values( - SerializeParams(err_packet{ - int2(1049), // eror code - string_fixed<1>({0x23}), // sql state marker - string_fixed<5>({'4', '2', '0', '0', '0'}), // sql state - string_eof("Unknown database 'a'") // err msg - }, { - 0x19, 0x04, 0x23, 0x34, 0x32, 0x30, 0x30, 0x30, 0x55, 0x6e, 0x6b, - 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x27, 0x61, 0x27 - }, "wrong_use_database"), - - SerializeParams(err_packet{ - int2(1146), // eror code - string_fixed<1>({0x23}), // sql state marker - string_fixed<5>({'4', '2', 'S', '0', '2'}), // sql state - string_eof("Table 'awesome.unknown' doesn't exist") // err msg - }, { - 0x7a, 0x04, 0x23, 0x34, 0x32, 0x53, 0x30, 0x32, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x27, 0x61, - 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x2e, 0x75, - 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x27, 0x20, - 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, - 0x65, 0x78, 0x69, 0x73, 0x74 - }, "unknown_table"), - - SerializeParams(err_packet{ - int2(1045), // error code - string_fixed<1>({0x23}), // SQL state marker - string_fixed<5>({'2', '8', '0', '0', '0'}), // SQL state - string_eof("Access denied for user 'root'@'localhost' (using password: YES)") - }, { - 0x15, 0x04, 0x23, 0x32, 0x38, 0x30, 0x30, 0x30, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x64, - 0x65, 0x6e, 0x69, 0x65, 0x64, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x27, - 0x72, 0x6f, 0x6f, 0x74, 0x27, 0x40, 0x27, 0x6c, - 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, - 0x27, 0x20, 0x28, 0x75, 0x73, 0x69, 0x6e, 0x67, - 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x3a, 0x20, 0x59, 0x45, 0x53, 0x29 - }, "failed_login") -), test_name_generator); - -constexpr std::uint8_t handshake_auth_plugin_data [] = { - 0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f, - 0x03, 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, - 0x43, 0x4a, 0x21, 0x62 -}; - -constexpr std::uint32_t hanshake_caps = - CLIENT_LONG_PASSWORD | - CLIENT_FOUND_ROWS | - CLIENT_LONG_FLAG | - CLIENT_CONNECT_WITH_DB | - CLIENT_NO_SCHEMA | - CLIENT_COMPRESS | - CLIENT_ODBC | - CLIENT_LOCAL_FILES | - CLIENT_IGNORE_SPACE | - CLIENT_PROTOCOL_41 | - CLIENT_INTERACTIVE | - CLIENT_IGNORE_SIGPIPE | - CLIENT_TRANSACTIONS | - CLIENT_RESERVED | // old flag, but set in this frame - CLIENT_SECURE_CONNECTION | // old flag, but set in this frame - CLIENT_MULTI_STATEMENTS | - CLIENT_MULTI_RESULTS | - CLIENT_PS_MULTI_RESULTS | - CLIENT_PLUGIN_AUTH | - CLIENT_CONNECT_ATTRS | - CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | - CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS | - CLIENT_SESSION_TRACK | - CLIENT_DEPRECATE_EOF | - CLIENT_REMEMBER_OPTIONS; - -INSTANTIATE_TEST_SUITE_P(Handhsake, DeserializeSpaceTest, ::testing::Values( - SerializeParams(handshake_packet{ - string_null("5.7.27-0ubuntu0.19.04.1"), // server version - int4(2), // connection ID - string_lenenc(makesv(handshake_auth_plugin_data)), - int4(hanshake_caps), - int1(static_cast(collation::latin1_swedish_ci)), - int2(SERVER_STATUS_AUTOCOMMIT), - string_null("mysql_native_password"), - {} // data buffer; internal, not used in the comparisons for correctness - }, { - 0x35, 0x2e, 0x37, 0x2e, 0x32, 0x37, 0x2d, 0x30, - 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x2e, - 0x31, 0x39, 0x2e, 0x30, 0x34, 0x2e, 0x31, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x52, 0x1a, 0x50, 0x3a, - 0x4b, 0x12, 0x70, 0x2f, 0x00, 0xff, 0xf7, 0x08, - 0x02, 0x00, 0xff, 0x81, 0x15, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, - 0x4a, 0x21, 0x62, 0x00, 0x6d, 0x79, 0x73, 0x71, - 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, - 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x00 - }, "regular") -), test_name_generator); - -constexpr std::uint8_t handshake_response_auth_data [] = { - 0xfe, 0xc6, 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, - 0xc5, 0x51, 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, - 0xe6, 0xfc, 0x34, 0xc9 -}; - -constexpr std::uint32_t handshake_response_caps = - CLIENT_LONG_PASSWORD | - CLIENT_LONG_FLAG | - CLIENT_LOCAL_FILES | - CLIENT_PROTOCOL_41 | - CLIENT_INTERACTIVE | - CLIENT_TRANSACTIONS | - CLIENT_SECURE_CONNECTION | - CLIENT_MULTI_STATEMENTS | - CLIENT_MULTI_RESULTS | - CLIENT_PS_MULTI_RESULTS | - CLIENT_PLUGIN_AUTH | - CLIENT_CONNECT_ATTRS | - CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | - CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS | - CLIENT_SESSION_TRACK | - CLIENT_DEPRECATE_EOF; - -INSTANTIATE_TEST_SUITE_P(HandhsakeResponse, SerializeTest, ::testing::Values( - SerializeParams(handshake_response_packet{ - int4(handshake_response_caps), - int4(16777216), // max packet size - int1(static_cast(collation::utf8_general_ci)), - string_null("root"), - string_lenenc(makesv(handshake_response_auth_data)), - string_null(""), // Irrelevant, not using connect with DB - string_null("mysql_native_password") // auth plugin name - }, { - 0x85, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, - 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51, - 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, - 0x34, 0xc9, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, - 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00 - }, "without_database", handshake_response_caps), - - SerializeParams(handshake_response_packet{ - int4(handshake_response_caps | CLIENT_CONNECT_WITH_DB), - int4(16777216), // max packet size - int1(static_cast(collation::utf8_general_ci)), - string_null("root"), - string_lenenc(makesv(handshake_response_auth_data)), - string_null("database"), // database name - string_null("mysql_native_password") // auth plugin name - }, { - 0x8d, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, - 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51, - 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, - 0x34, 0xc9, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, - 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x00 - }, "with_database", handshake_response_caps | CLIENT_CONNECT_WITH_DB) -), test_name_generator); - -constexpr std::uint8_t auth_switch_request_auth_data [] = { - 0x49, 0x49, 0x7e, 0x51, 0x5d, 0x1f, 0x19, 0x6a, - 0x0f, 0x5a, 0x63, 0x15, 0x3e, 0x28, 0x31, 0x3e, - 0x3c, 0x79, 0x09, 0x7c -}; - -INSTANTIATE_TEST_SUITE_P(AuthSwitchRequest, DeserializeTest, testing::Values( - SerializeParams(auth_switch_request_packet{ - string_null("mysql_native_password"), - string_eof(makesv(auth_switch_request_auth_data)) - }, { - 0x6d, 0x79, 0x73, - 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, - 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x00, 0x49, 0x49, 0x7e, 0x51, 0x5d, - 0x1f, 0x19, 0x6a, 0x0f, 0x5a, 0x63, 0x15, 0x3e, - 0x28, 0x31, 0x3e, 0x3c, 0x79, 0x09, 0x7c, 0x00 - }, "regular") -), test_name_generator); - -constexpr std::uint8_t auth_switch_response_auth_data [] = { - 0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, - 0x91, 0xff, 0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, - 0x88, 0x2d, 0xf9, 0xcf -}; - -INSTANTIATE_TEST_SUITE_P(AuthSwitchResponse, SerializeTest, testing::Values( - SerializeParams(auth_switch_response_packet{ - string_eof(makesv(auth_switch_response_auth_data)) - }, { - 0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, - 0x91, 0xff, 0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, - 0x88, 0x2d, 0xf9, 0xcf - }, "regular") -), test_name_generator); - -// Column definition -INSTANTIATE_TEST_SUITE_P(ColumnDefinition, DeserializeSpaceTest, testing::Values( - SerializeParams(column_definition_packet{ - string_lenenc("def"), //catalog - string_lenenc("awesome"), // schema (database) - string_lenenc("test_table"), // table - string_lenenc("test_table"), // physical table - string_lenenc("id"), // field name - string_lenenc("id"), // physical field name - collation::binary, - int4(11), // length - protocol_field_type::long_, - int2( - column_flags::not_null | - column_flags::pri_key | - column_flags::auto_increment | - column_flags::part_key - ), - int1(0) // decimals - }, { - 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, - 0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73, - 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, - 0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x02, 0x69, 0x64, 0x02, 0x69, 0x64, - 0x0c, 0x3f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, - 0x03, 0x42, 0x00, 0x00, 0x00 - }, "numeric_auto_increment_primary_key"), - SerializeParams(column_definition_packet{ - string_lenenc("def"), //catalog - string_lenenc("awesome"), // schema (database) - string_lenenc("child"), // table - string_lenenc("child_table"), // physical table - string_lenenc("field_alias"), // field name - string_lenenc("field_varchar"), // physical field name - collation::utf8_general_ci, - int4(765), // length - protocol_field_type::var_string, - int2(), // no column flags - int1(0) // decimals - }, { - 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, - 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68, 0x69, - 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, - 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0b, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, - 0x61, 0x73, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, - 0x0c, 0x21, 0x00, 0xfd, 0x02, 0x00, 0x00, 0xfd, - 0x00, 0x00, 0x00, 0x00, 0x00 - }, "varchar_field_aliased_field_and_table_names_join"), - - SerializeParams(column_definition_packet{ - string_lenenc("def"), //catalog - string_lenenc("awesome"), // schema (database) - string_lenenc("test_table"), // table - string_lenenc("test_table"), // physical table - string_lenenc("field_float"), // field name - string_lenenc("field_float"), // physical field name - collation::binary, // binary - int4(12), // length - protocol_field_type::float_, - int2(), // no column flags - int1(31) // decimals - }, { - 0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, - 0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73, - 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, - 0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f, - 0x61, 0x74, 0x0c, 0x3f, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x00 - }, "float_field") -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(ComQuery, SerializeTest, testing::Values( - SerializeParams(com_query_packet{ - string_eof("show databases") - }, { - 0x03, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73 - }, "regular") -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(ComStmtPrepare, SerializeTest, testing::Values( - SerializeParams(com_stmt_prepare_packet{ - string_eof("SELECT * from three_rows_table WHERE id = ?") - }, { - 0x16, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, - 0x2a, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, - 0x68, 0x72, 0x65, 0x65, 0x5f, 0x72, 0x6f, 0x77, - 0x73, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, - 0x57, 0x48, 0x45, 0x52, 0x45, 0x20, 0x69, 0x64, - 0x20, 0x3d, 0x20, 0x3f - }, "regular") -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(ComStmtPrepareResponse, DeserializeSpaceTest, testing::Values( - SerializeParams(com_stmt_prepare_ok_packet{ - int4(1), // statement id - int2(2), // number of fields - int2(3), // number of params - int2(0), // warnings - }, { - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00 - }, "regular") -), test_name_generator); - -// Helper for composing ComStmtExecute tests -template > -SerializeParams make_stmt_execute_test( - std::uint32_t stmt_id, - std::uint8_t flags, - std::uint32_t itercount, - std::uint8_t new_params_flag, - std::vector&& params, - std::vector&& buffer, - std::string&& test_name -) -{ - auto params_shared = std::make_shared(std::begin(params), std::end(params)); - return SerializeParams( - com_stmt_execute_packet { - int4(stmt_id), - int1(flags), - int4(itercount), - int1(new_params_flag), - params_shared->begin(), - params_shared->end() - }, - std::move(buffer), - std::move(test_name), - 0, // capabilities - params_shared - ); -} - -INSTANTIATE_TEST_SUITE_P(ComStmtExecute, SerializeTest, testing::Values( - make_stmt_execute_test(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params - { std::uint32_t(0xabffff) }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x03, 0x80, 0xff, 0xff, - 0xab, 0x00 - }, - "uint32_t" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { std::int32_t(-0xabffff) }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, - 0x54, 0xff - }, - "int32_t" - ), - make_stmt_execute_test(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params - { 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 - }, - "uint64_t" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { 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 - }, - "int64_t" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { std::string_view("test") }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x04, 0x74, - 0x65, 0x73, 0x74 - }, - "string_view" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { 3.14e20f }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x2d, - 0x88, 0x61 - }, - "float" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { 2.1e214 }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x56, 0xc0, - 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c - }, - "double" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { makedate(2010, 9, 3) }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x04, 0xda, - 0x07, 0x09, 0x03 - }, - "date" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { 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, - 0x03, 0x00 - }, - "datetime" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { 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, - 0x89, 0x03, 0x00 - }, - "time" - ), - make_stmt_execute_test(1, 0, 1, 1, // stmt ID, flags, itercount, new params - { nullptr }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x06, 0x00 - }, - "null" - ), - make_stmt_execute_test(2, 0, 1, 1, makevalues( - std::uint32_t(0xabffff), - std::int32_t(-0xabffff), - std::uint64_t(0xabffffabacadae), - std::int64_t(-0xabffffabacadae), - std::string_view("test"), - nullptr, - 2.1e214, - makedate(2010, 9, 3), - makedt(2010, 9, 3, 10, 30, 59, 231800), - maket(230, 30, 59, 231800), - nullptr - ), { - 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x20, 0x04, 0x01, 0x03, 0x80, 0x03, - 0x00, 0x08, 0x80, 0x08, 0x00, 0x0f, 0x00, 0x06, - 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0b, - 0x00, 0x06, 0x00, 0xff, 0xff, 0xab, 0x00, 0x01, - 0x00, 0x54, 0xff, 0xae, 0xad, 0xac, 0xab, 0xff, - 0xff, 0xab, 0x00, 0x52, 0x52, 0x53, 0x54, 0x00, - 0x00, 0x54, 0xff, 0x04, 0x74, 0x65, 0x73, 0x74, - 0x56, 0xc0, 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c, - 0x04, 0xda, 0x07, 0x09, 0x03, 0x0b, 0xda, 0x07, - 0x09, 0x03, 0x0a, 0x1e, 0x3b, 0x78, 0x89, 0x03, - 0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, - 0x1e, 0x3b, 0x78, 0x89, 0x03, 0x00 - }, - "several_params" - ), - make_stmt_execute_test>(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params - { std::uint32_t(0xabffff) }, { - 0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x03, 0x80, 0xff, 0xff, - 0xab, 0x00 - }, - "forward_list_iterator" - ) -), test_name_generator); - -INSTANTIATE_TEST_SUITE_P(ComStmtClose, SerializeTest, testing::Values( - SerializeParams(com_stmt_close_packet{int4(1)}, {0x19, 0x01, 0x00, 0x00, 0x00}, "regular") + serialization_testcase(maket(0, 0, 0), + {0x00}, "zero"), + serialization_testcase(maket(48, 0, 0, 0), + {0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "positive_d"), + serialization_testcase(maket(21, 0, 0, 0), + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00}, "positive_h"), + serialization_testcase(maket(0, 40, 0), + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00}, "positive_m"), + serialization_testcase(maket(0, 0, 21), + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15}, "positive_s"), + serialization_testcase(maket(0, 0, 0, 321000), + {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}, "positive_u"), + serialization_testcase(maket(838, 59, 58, 999000), + {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}, "positive_hmsu"), + serialization_testcase(-maket(48, 0, 0, 0), + {0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "negative_d"), + serialization_testcase(-maket(21, 0, 0, 0), + {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00}, "negative_h"), + serialization_testcase(-maket(0, 40, 0), + {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00}, "negative_m"), + serialization_testcase(-maket(0, 0, 21), + {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15}, "negative_s"), + serialization_testcase(-maket(0, 0, 0, 321000), + {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}, "negative_u"), + serialization_testcase(-maket(838, 59, 58, 999000), + {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}, "negative_hmsu") ), test_name_generator); diff --git a/test/unit/detail/protocol/serialization_test_common.cpp b/test/unit/detail/protocol/serialization_test_common.cpp new file mode 100644 index 00000000..38cbbf74 --- /dev/null +++ b/test/unit/detail/protocol/serialization_test_common.cpp @@ -0,0 +1,124 @@ + +#include "serialization_test_common.hpp" + +using namespace boost::mysql::detail; +using namespace boost::mysql::test; +using boost::mysql::errc; + +namespace +{ + +// Test bodies +void get_size_test(const serialization_testcase& p) +{ + serialization_context ctx (p.caps, nullptr); + auto size = p.value->get_size(ctx); + EXPECT_EQ(size, p.expected_buffer.size()); +} + +// serialize +void serialize_test(const serialization_testcase& p) +{ + auto expected_size = p.expected_buffer.size(); + std::vector buffer (expected_size + 8, 0x7a); // buffer overrun detector + serialization_context ctx (p.caps, buffer.data()); + p.value->serialize(ctx); + + // Iterator + EXPECT_EQ(ctx.first(), buffer.data() + expected_size) << "Iterator not updated correctly"; + + // Buffer + std::string_view expected_populated = makesv(p.expected_buffer.data(), expected_size); + std::string_view actual_populated = makesv(buffer.data(), expected_size); + compare_buffers(expected_populated, actual_populated, "Buffer contents incorrect"); + + // Check for buffer overruns + std::string expected_clean (8, 0x7a); + std::string_view actual_clean = makesv(buffer.data() + expected_size, 8); + compare_buffers(expected_clean, actual_clean, "Buffer overrun"); +} + +// deserialize +void deserialize_test(const serialization_testcase& p) +{ + auto first = p.expected_buffer.data(); + auto size = p.expected_buffer.size(); + deserialization_context ctx (first, first + size, p.caps); + auto actual_value = p.value->default_construct(); + auto err = actual_value->deserialize(ctx); + + // No error + EXPECT_EQ(err, errc::ok); + + // Iterator advanced + EXPECT_EQ(ctx.first(), first + size); + + // Actual value + EXPECT_EQ(*actual_value, *p.value); +} + +void deserialize_extra_space_test(const serialization_testcase& p) +{ + std::vector buffer (p.expected_buffer); + buffer.push_back(0xff); + auto first = buffer.data(); + deserialization_context ctx (first, first + buffer.size(), p.caps); + auto actual_value = p.value->default_construct(); + auto err = actual_value->deserialize(ctx); + + // No error + EXPECT_EQ(err, errc::ok); + + // Iterator advanced + EXPECT_EQ(ctx.first(), first + p.expected_buffer.size()); + + // Actual value + EXPECT_EQ(*actual_value, *p.value); +} + +void deserialize_not_enough_space_test(const serialization_testcase& p) +{ + std::vector buffer (p.expected_buffer); + buffer.back() = 0x7a; // try to detect any overruns + deserialization_context ctx (buffer.data(), buffer.data() + buffer.size() - 1, p.caps); + auto actual_value = p.value->default_construct(); + auto err = actual_value->deserialize(ctx); + EXPECT_EQ(err, errc::incomplete_message); +} + +// Fixture test definition +TEST_P(SerializeTest, get_size) { get_size_test(GetParam()); } +TEST_P(SerializeTest, serialize) { serialize_test(GetParam()); } + +TEST_P(DeserializeTest, deserialize) { deserialize_test(GetParam()); } + +TEST_P(DeserializeSpaceTest, deserialize) { deserialize_test(GetParam()); } +TEST_P(DeserializeSpaceTest, deserialize_extra_space) { deserialize_extra_space_test(GetParam()); } +TEST_P(DeserializeSpaceTest, deserialize_not_enough_space) { deserialize_not_enough_space_test(GetParam()); } + +TEST_P(SerializeDeserializeTest, get_size) { get_size_test(GetParam()); } +TEST_P(SerializeDeserializeTest, serialize) { serialize_test(GetParam()); } +TEST_P(SerializeDeserializeTest, deserialize) { deserialize_test(GetParam()); } + +TEST_P(FullSerializationTest, get_size) { get_size_test(GetParam()); } +TEST_P(FullSerializationTest, serialize) { serialize_test(GetParam()); } +TEST_P(FullSerializationTest, deserialize) { deserialize_test(GetParam()); } +TEST_P(FullSerializationTest, deserialize_extra_space) { deserialize_extra_space_test(GetParam()); } +TEST_P(FullSerializationTest, deserialize_not_enough_space) { deserialize_not_enough_space_test(GetParam()); } + +// Errc tests +TEST_P(DeserializeErrorTest, Deserialize_ErrorCondition_ReturnsErrorCode) +{ + auto first = GetParam().buffer.data(); + auto last = GetParam().buffer.data() + GetParam().buffer.size(); + deserialization_context ctx (first, last, capabilities()); + auto value = GetParam().value->default_construct(); + auto err = value->deserialize(ctx); + EXPECT_EQ(err, GetParam().expected_error); +} + +} // anon namespace + + + + diff --git a/test/unit/detail/protocol/serialization_test_common.hpp b/test/unit/detail/protocol/serialization_test_common.hpp new file mode 100644 index 00000000..8e039b78 --- /dev/null +++ b/test/unit/detail/protocol/serialization_test_common.hpp @@ -0,0 +1,201 @@ +#ifndef TEST_SERIALIZATION_TEST_COMMON_HPP_ +#define TEST_SERIALIZATION_TEST_COMMON_HPP_ + +#include "boost/mysql/detail/protocol/serialization.hpp" +#include "boost/mysql/detail/protocol/constants.hpp" +#include "boost/mysql/value.hpp" +#include +#include +#include +#include +#include "test_common.hpp" + +namespace boost { +namespace mysql { +namespace test { + +template +std::ostream& operator<<(std::ostream& os, const std::array& v) +{ + return os << std::string_view(v.data(), N); +} + +inline std::ostream& operator<<(std::ostream& os, std::uint8_t value) +{ + return os << +value; +} +using ::date::operator<<; + +// Operator == for structs +template +bool equals_struct(const T& lhs, const T& rhs) +{ + constexpr auto fields = detail::get_struct_fields::value; + if constexpr (index == std::tuple_size::value) + { + return true; + } + else + { + constexpr auto pmem = std::get(fields); + return (rhs.*pmem == lhs.*pmem) && equals_struct(lhs, rhs); + } +} + +template +std::enable_if_t(), bool> +operator==(const T& lhs, const T& rhs) +{ + return equals_struct<0>(lhs, rhs); +} + +// Operator << for value_holder +template +std::ostream& operator<<(std::ostream& os, const detail::value_holder& value) +{ + return os << value.value; +} + +template +std::enable_if_t, std::ostream&> +operator<<(std::ostream& os, T value) +{ + return os << boost::typeindex::type_id().pretty_name() << "(" << + static_cast>(value) << ")"; +} + +// Operator << for structs +template +void print_struct(std::ostream& os, const T& value) +{ + constexpr auto fields = detail::get_struct_fields::value; + if constexpr (index < std::tuple_size::value) + { + constexpr auto pmem = std::get(fields); + os << " " << (value.*pmem) << ",\n"; + print_struct(os, value); + } +} + +template +std::enable_if_t(), std::ostream&> +operator<<(std::ostream& os, const T& value) +{ + os << boost::typeindex::type_id().pretty_name() << "(\n"; + print_struct<0>(os, value); + os << ")\n"; + return os; +} + +class any_value +{ +public: + virtual ~any_value() {} + virtual void serialize(detail::serialization_context& ctx) const = 0; + virtual std::size_t get_size(const detail::serialization_context& ctx) const = 0; + virtual errc deserialize(detail::deserialization_context& ctx) = 0; + virtual std::shared_ptr default_construct() const = 0; + virtual bool equals(const any_value& rhs) const = 0; + virtual void print(std::ostream& os) const = 0; + + bool operator==(const any_value& rhs) const { return equals(rhs); } +}; +inline std::ostream& operator<<(std::ostream& os, const any_value& value) +{ + value.print(os); + return os; +} + +template +class any_value_impl : public any_value +{ + T value_; +public: + any_value_impl(const T& v): value_(v) {}; + void serialize(detail::serialization_context& ctx) const override + { + ::boost::mysql::detail::serialize(value_, ctx); + } + std::size_t get_size(const detail::serialization_context& ctx) const override + { + return ::boost::mysql::detail::get_size(value_, ctx); + } + errc deserialize(detail::deserialization_context& ctx) override + { + return ::boost::mysql::detail::deserialize(value_, ctx); + } + std::shared_ptr default_construct() const override + { + return std::make_shared>(T{}); + } + bool equals(const any_value& rhs) const override + { + auto typed_value = dynamic_cast*>(&rhs); + return typed_value && (typed_value->value_ == value_); + } + void print(std::ostream& os) const override + { + os << value_; + } +}; + +struct serialization_testcase : test::named_param +{ + std::shared_ptr value; + std::vector expected_buffer; + std::string name; + detail::capabilities caps; + std::any additional_storage; + + template + serialization_testcase(const T& v, std::vector&& buff, + std::string&& name, std::uint32_t caps=0, std::any storage = {}): + value(std::make_shared>(v)), + expected_buffer(move(buff)), + name(move(name)), + caps(caps), + additional_storage(std::move(storage)) + { + } +}; + + + +// Test fixtures +struct SerializationFixture : public testing::TestWithParam {}; // base +struct SerializeTest : SerializationFixture {}; // Only serialization +struct DeserializeTest : SerializationFixture {}; // Only deserialization +struct DeserializeSpaceTest : SerializationFixture {}; // Deserialization + extra/infra space +struct SerializeDeserializeTest : SerializationFixture {}; // Serialization + deserialization +struct FullSerializationTest : SerializationFixture {}; // All + +// errc tests +struct deserialize_error_testcase : test::named_param +{ + std::shared_ptr value; + std::vector buffer; + std::string name; + errc expected_error; + + template + deserialize_error_testcase( + std::vector&& buffer, + std::string&& test_name, + errc err = errc::incomplete_message + ) : + value(std::make_shared>(T{})), + buffer(std::move(buffer)), + name(std::move(test_name)), + expected_error(err) + { + } +}; + +struct DeserializeErrorTest : testing::TestWithParam {}; + +} // test +} // mysql +} // boost + + +#endif /* TEST_SERIALIZATION_TEST_COMMON_HPP_ */