/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_ #define UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_ #include #include #include #include "plugin/x/protocol/encoders/encoding_xprotocol.h" namespace protocol { namespace test { class Encoder_validator { private: std::string get_location() { if (m_message_started) { return "(field: " + std::to_string(m_field_number) + ")"; } return "(operation-index:" + std::to_string(m_field_number + m_raw_data_number) + ")"; } void check_size(const char *info) { if (m_buffer_left < 0) FAIL() << "Buffer underflow at " << info << get_location() << ", please increase the buffer in begin_xmessage or " "ensure_buffer_size call"; } public: void summarize_buffer(const char *info) { if (m_buffer_left > 0 && !m_allow_not_used_data) { FAIL() << "Buffer was not filled to its boundaries at " << info << ", not used space: " << m_buffer_left; } if (m_buffer_left < 0) { FAIL() << "Buffer is too small at " << info << ", we need additional: " << -m_buffer_left << " bytes, in total: " << -m_buffer_left + m_buffer_size; } } using Position = XProtocol_encoder::Position; template using Field_delimiter = XProtocol_encoder::Field_delimiter; void configure_allow_bigger_buffers(const bool allow_bigger_buffers) { m_allow_not_used_data = allow_bigger_buffers; } template void ensure_buffer_size() { m_buffer_size = m_buffer_left = size; } template Position begin_xmessage() { if (m_message_started) { ADD_FAILURE() << "Message already started"; return {}; } m_buffer_size = m_buffer_left = needed_size; m_buffer_left -= k_xmsg_header_size; return {}; } template void begin_xmessage(Position *position) { *position = begin_xmessage(); } void end_xmessage(const Position &) { if (m_message_ended) { FAIL() << "Message already finished"; } summarize_buffer("end_xmessage"); } void abort_xmessage(const Position &position) { end_xmessage(position); } void encode_fixed_uint32(const uint32_t) { ++m_raw_data_number; m_buffer_left -= k_fixed32_size; check_size("encode_raw_data_fixed_uint32"); } void encode_fixed_uint64(const uint64_t) { ++m_raw_data_number; m_buffer_left -= k_fixed64_size; check_size("encode_raw_data_fixed_uint64"); } void encode_fixedvar16_uint32(const uint32_t) { ++m_raw_data_number; m_buffer_left -= k_fixed16_size; check_size("encode_raw_data_fixedvar16_uint32"); } void encode_fixedvar8_uint8(const uint8_t) { ++m_raw_data_number; m_buffer_left -= k_fixed8_size; check_size("encode_raw_data_fixedvar8_uint8"); } void encode_var_uint32(const uint32_t) { ++m_raw_data_number; m_buffer_left -= (k_varint32_size); check_size("encode_raw_data_uint32"); } void encode_var_uint64(const uint64_t) { ++m_raw_data_number; m_buffer_left -= (k_varint64_size); check_size("encode_raw_data_uint64"); } void encode_var_sint64(const int64_t) { ++m_raw_data_number; m_buffer_left -= (k_varint64_size); check_size("encode_raw_data_sint64"); } template void encode_const_var_uint() { ++m_raw_data_number; m_buffer_left -= (k_varint64_size); check_size("encode_raw_data_uint64_template"); } template void encode_field_delimited_header() { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size); check_size("encode_field_delimited"); } template void encode_field_enum(const int32_t) { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint32_size); check_size("encode_field_enum"); } template void encode_optional_field_var_uint64(const uint64_t *) { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("encode_optional_field_var_uint64"); } template void encode_optional_field_var_uint32(const uint32_t *) { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint32_size); check_size("encode_optional_field_var_uint32"); } template void encode_field_string(const std::string &) { ++m_field_number; summarize_buffer("encode_field_string"); m_buffer_left = 0; } template void encode_field_const_var_uint() { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("encode_field_const_var_uint"); } template void encode_field_const_enum() { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("encode_field_const_enum"); } template void encode_field_var_uint32(const uint32_t) { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("k_varint32_size"); } template Field_delimiter begin_delimited_field() { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("begin_delimited_field"); return {}; } template void end_delimited_field(const Field_delimiter &) { // check_size("end_delimited_field"); } template void encode_field_var_uint64(const uint64_t) { ++m_field_number; m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size); check_size("encode_field_var_uint64"); } void encode_raw(const uint8_t *, uint32_t) { m_buffer_left = 0; } template void empty_xmessage() { if (m_message_started) { FAIL() << "Message already started"; } if (m_message_ended) { FAIL() << "Message already ended"; } m_message_started = true; m_message_ended = true; check_size("empty_xmessage"); } private: const int k_varint_field_prefix_size = 10; const int k_varint32_size = 5; const int k_varint64_size = 10; const int k_fixed8_size = 1; const int k_fixed16_size = 2; const int k_fixed32_size = 4; const int k_fixed64_size = 8; const int k_xmsg_header_size = 5; bool m_message_started = false; bool m_message_ended = false; int64_t m_buffer_left = 0; int64_t m_buffer_size = 0; int m_field_number = 0; int m_raw_data_number = 0; bool m_allow_not_used_data = false; }; } // namespace test } // namespace protocol #endif // UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_