1 /* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License, version 2.0,
5  as published by the Free Software Foundation.
6 
7  This program is also distributed with certain software (including
8  but not limited to OpenSSL) that is licensed under separate terms,
9  as designated in a particular file or component or in included license
10  documentation.  The authors of MySQL hereby grant you an additional
11  permission to link the program and your derivative works with the
12  separately licensed software that they have included with MySQL.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License, version 2.0, for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_
24 #define UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_
25 
26 #include <gtest/gtest.h>
27 #include <stddef.h>
28 #include <string>
29 
30 #include "plugin/x/protocol/encoders/encoding_xprotocol.h"
31 
32 namespace protocol {
33 
34 namespace test {
35 
36 class Encoder_validator {
37  private:
get_location()38   std::string get_location() {
39     if (m_message_started) {
40       return "(field: " + std::to_string(m_field_number) + ")";
41     }
42     return "(operation-index:" +
43            std::to_string(m_field_number + m_raw_data_number) + ")";
44   }
45 
check_size(const char * info)46   void check_size(const char *info) {
47     if (m_buffer_left < 0)
48       FAIL() << "Buffer underflow at " << info << get_location()
49              << ", please increase the buffer in begin_xmessage or "
50                 "ensure_buffer_size call";
51   }
52 
53  public:
summarize_buffer(const char * info)54   void summarize_buffer(const char *info) {
55     if (m_buffer_left > 0 && !m_allow_not_used_data) {
56       FAIL() << "Buffer was not filled to its boundaries at " << info
57              << ", not used space: " << m_buffer_left;
58     }
59 
60     if (m_buffer_left < 0) {
61       FAIL() << "Buffer is too small at " << info
62              << ", we need additional: " << -m_buffer_left
63              << " bytes, in total: " << -m_buffer_left + m_buffer_size;
64     }
65   }
66 
67   using Position = XProtocol_encoder::Position;
68 
69   template <uint32_t t>
70   using Field_delimiter = XProtocol_encoder::Field_delimiter<t>;
71 
configure_allow_bigger_buffers(const bool allow_bigger_buffers)72   void configure_allow_bigger_buffers(const bool allow_bigger_buffers) {
73     m_allow_not_used_data = allow_bigger_buffers;
74   }
75 
76   template <uint32_t size>
ensure_buffer_size()77   void ensure_buffer_size() {
78     m_buffer_size = m_buffer_left = size;
79   }
80 
81   template <uint32_t id, uint32_t needed_size>
begin_xmessage()82   Position begin_xmessage() {
83     if (m_message_started) {
84       ADD_FAILURE() << "Message already started";
85       return {};
86     }
87 
88     m_buffer_size = m_buffer_left = needed_size;
89     m_buffer_left -= k_xmsg_header_size;
90 
91     return {};
92   }
93 
94   template <uint32_t id, uint32_t needed_size>
begin_xmessage(Position * position)95   void begin_xmessage(Position *position) {
96     *position = begin_xmessage<id, needed_size>();
97   }
98 
end_xmessage(const Position &)99   void end_xmessage(const Position &) {
100     if (m_message_ended) {
101       FAIL() << "Message already finished";
102     }
103 
104     summarize_buffer("end_xmessage");
105   }
106 
abort_xmessage(const Position & position)107   void abort_xmessage(const Position &position) { end_xmessage(position); }
108 
encode_fixed_uint32(const uint32_t)109   void encode_fixed_uint32(const uint32_t) {
110     ++m_raw_data_number;
111     m_buffer_left -= k_fixed32_size;
112 
113     check_size("encode_raw_data_fixed_uint32");
114   }
115 
encode_fixed_uint64(const uint64_t)116   void encode_fixed_uint64(const uint64_t) {
117     ++m_raw_data_number;
118     m_buffer_left -= k_fixed64_size;
119 
120     check_size("encode_raw_data_fixed_uint64");
121   }
122 
encode_fixedvar16_uint32(const uint32_t)123   void encode_fixedvar16_uint32(const uint32_t) {
124     ++m_raw_data_number;
125     m_buffer_left -= k_fixed16_size;
126 
127     check_size("encode_raw_data_fixedvar16_uint32");
128   }
129 
encode_fixedvar8_uint8(const uint8_t)130   void encode_fixedvar8_uint8(const uint8_t) {
131     ++m_raw_data_number;
132     m_buffer_left -= k_fixed8_size;
133 
134     check_size("encode_raw_data_fixedvar8_uint8");
135   }
136 
encode_var_uint32(const uint32_t)137   void encode_var_uint32(const uint32_t) {
138     ++m_raw_data_number;
139     m_buffer_left -= (k_varint32_size);
140 
141     check_size("encode_raw_data_uint32");
142   }
143 
encode_var_uint64(const uint64_t)144   void encode_var_uint64(const uint64_t) {
145     ++m_raw_data_number;
146     m_buffer_left -= (k_varint64_size);
147 
148     check_size("encode_raw_data_uint64");
149   }
150 
encode_var_sint64(const int64_t)151   void encode_var_sint64(const int64_t) {
152     ++m_raw_data_number;
153     m_buffer_left -= (k_varint64_size);
154 
155     check_size("encode_raw_data_sint64");
156   }
157 
158   template <uint64_t value>
encode_const_var_uint()159   void encode_const_var_uint() {
160     ++m_raw_data_number;
161     m_buffer_left -= (k_varint64_size);
162 
163     check_size("encode_raw_data_uint64_template");
164   }
165 
166   template <uint32_t field_id>
encode_field_delimited_header()167   void encode_field_delimited_header() {
168     ++m_field_number;
169     m_buffer_left -= (k_varint_field_prefix_size);
170 
171     check_size("encode_field_delimited");
172   }
173 
174   template <uint32_t field_id>
encode_field_enum(const int32_t)175   void encode_field_enum(const int32_t) {
176     ++m_field_number;
177     m_buffer_left -= (k_varint_field_prefix_size + k_varint32_size);
178 
179     check_size("encode_field_enum");
180   }
181 
182   template <uint32_t field_id>
encode_optional_field_var_uint64(const uint64_t *)183   void encode_optional_field_var_uint64(const uint64_t *) {
184     ++m_field_number;
185     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
186 
187     check_size("encode_optional_field_var_uint64");
188   }
189 
190   template <uint32_t field_id>
encode_optional_field_var_uint32(const uint32_t *)191   void encode_optional_field_var_uint32(const uint32_t *) {
192     ++m_field_number;
193     m_buffer_left -= (k_varint_field_prefix_size + k_varint32_size);
194 
195     check_size("encode_optional_field_var_uint32");
196   }
197 
198   template <uint32_t field_id>
encode_field_string(const std::string &)199   void encode_field_string(const std::string &) {
200     ++m_field_number;
201     summarize_buffer("encode_field_string");
202     m_buffer_left = 0;
203   }
204 
205   template <uint32_t field_id, uint64_t value>
encode_field_const_var_uint()206   void encode_field_const_var_uint() {
207     ++m_field_number;
208     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
209 
210     check_size("encode_field_const_var_uint");
211   }
212 
213   template <uint32_t field_id, int64_t value>
encode_field_const_enum()214   void encode_field_const_enum() {
215     ++m_field_number;
216     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
217 
218     check_size("encode_field_const_enum");
219   }
220 
221   template <uint32_t field_id>
encode_field_var_uint32(const uint32_t)222   void encode_field_var_uint32(const uint32_t) {
223     ++m_field_number;
224     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
225 
226     check_size("k_varint32_size");
227   }
228 
229   template <uint32_t id, uint32_t delimiter_length = 1>
begin_delimited_field()230   Field_delimiter<delimiter_length> begin_delimited_field() {
231     ++m_field_number;
232     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
233 
234     check_size("begin_delimited_field");
235 
236     return {};
237   }
238 
239   template <uint32_t delimiter_length>
end_delimited_field(const Field_delimiter<delimiter_length> &)240   void end_delimited_field(const Field_delimiter<delimiter_length> &) {
241     // check_size("end_delimited_field");
242   }
243 
244   template <uint32_t field_id>
encode_field_var_uint64(const uint64_t)245   void encode_field_var_uint64(const uint64_t) {
246     ++m_field_number;
247     m_buffer_left -= (k_varint_field_prefix_size + k_varint64_size);
248 
249     check_size("encode_field_var_uint64");
250   }
251 
encode_raw(const uint8_t *,uint32_t)252   void encode_raw(const uint8_t *, uint32_t) { m_buffer_left = 0; }
253 
254   template <uint32_t id>
empty_xmessage()255   void empty_xmessage() {
256     if (m_message_started) {
257       FAIL() << "Message already started";
258     }
259 
260     if (m_message_ended) {
261       FAIL() << "Message already ended";
262     }
263 
264     m_message_started = true;
265     m_message_ended = true;
266     check_size("empty_xmessage");
267   }
268 
269  private:
270   const int k_varint_field_prefix_size = 10;
271   const int k_varint32_size = 5;
272   const int k_varint64_size = 10;
273   const int k_fixed8_size = 1;
274   const int k_fixed16_size = 2;
275   const int k_fixed32_size = 4;
276   const int k_fixed64_size = 8;
277   const int k_xmsg_header_size = 5;
278 
279   bool m_message_started = false;
280   bool m_message_ended = false;
281   int64_t m_buffer_left = 0;
282   int64_t m_buffer_size = 0;
283   int m_field_number = 0;
284   int m_raw_data_number = 0;
285   bool m_allow_not_used_data = false;
286 };
287 
288 }  // namespace test
289 
290 }  // namespace protocol
291 
292 #endif  // UNITTEST_GUNIT_XPLUGIN_XPL_ENCODER_VALIDATOR_H_
293