Line data Source code
1 : // Copyright (c) 2011-2024 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : /** \file
20 : * \brief Verify the BRS functions.
21 : *
22 : * This file implements tests to verify that the BRS functions do what
23 : * they are expected to do.
24 : */
25 :
26 : // self
27 : //
28 : #include "catch_main.h"
29 :
30 :
31 : // snapdev
32 : //
33 : #include <snapdev/brs.h>
34 :
35 :
36 : // C++
37 : //
38 : #include <fstream>
39 :
40 :
41 :
42 :
43 1 : CATCH_TEST_CASE("bitfield_size", "[serialization][math]")
44 : {
45 1 : CATCH_START_SECTION("brs: push/restore char")
46 : {
47 1 : constexpr std::size_t const sizeof_type(SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_type));
48 1 : CATCH_REQUIRE(sizeof_type == 2);
49 :
50 1 : constexpr std::size_t const sizeof_name(SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_name));
51 1 : CATCH_REQUIRE(sizeof_name == 7);
52 :
53 1 : constexpr std::size_t const sizeof_hunk(SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_hunk));
54 1 : CATCH_REQUIRE(sizeof_hunk == 23);
55 : }
56 1 : CATCH_END_SECTION()
57 1 : }
58 :
59 :
60 13 : CATCH_TEST_CASE("basic_types", "[serialization]")
61 : {
62 13 : CATCH_START_SECTION("brs: push/restore char")
63 : {
64 1 : std::stringstream buffer;
65 1 : snapdev::serializer out(buffer);
66 :
67 1 : std::string data(buffer.str());
68 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
69 :
70 1 : CATCH_REQUIRE(data[0] == 'B');
71 1 : CATCH_REQUIRE(data[1] == 'R');
72 1 : CATCH_REQUIRE(data[2] == 'L');
73 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
74 :
75 1 : char value = 33;
76 1 : out.add_value("orange", value);
77 :
78 3 : CATCH_REQUIRE_THROWS_MATCHES(
79 : out.add_value(std::string(), &value, sizeof(value))
80 : , snapdev::brs_cannot_be_empty
81 : , Catch::Matchers::ExceptionMessage(
82 : "brs_error: name cannot be an empty string"));
83 :
84 : // make sure it did not get smashed
85 1 : data = buffer.str();
86 1 : CATCH_REQUIRE(data[0] == 'B');
87 1 : CATCH_REQUIRE(data[1] == 'R');
88 1 : CATCH_REQUIRE(data[2] == 'L');
89 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
90 :
91 1 : CATCH_REQUIRE(data[4] == 6 << 2); // hunk_sizes_t
92 1 : CATCH_REQUIRE(data[5] == 1 << 1);
93 1 : CATCH_REQUIRE(data[6] == 0);
94 1 : CATCH_REQUIRE(data[7] == 0);
95 :
96 1 : CATCH_REQUIRE(data[8] == 'o'); // name
97 1 : CATCH_REQUIRE(data[9] == 'r');
98 1 : CATCH_REQUIRE(data[10] == 'a');
99 1 : CATCH_REQUIRE(data[11] == 'n');
100 1 : CATCH_REQUIRE(data[12] == 'g');
101 1 : CATCH_REQUIRE(data[13] == 'e');
102 :
103 1 : CATCH_REQUIRE(data[14] == 33); // value
104 :
105 : struct processor
106 : {
107 1 : static bool process_hunk(
108 : snapdev::deserializer<std::stringstream> & in
109 : , snapdev::field_t const & field)
110 : {
111 1 : CATCH_REQUIRE(field.f_name == "orange");
112 1 : CATCH_REQUIRE(field.f_sub_name.empty());
113 1 : CATCH_REQUIRE(field.f_index == -1);
114 1 : CATCH_REQUIRE(field.f_size == 1);
115 1 : char c;
116 1 : in.read_data(c);
117 1 : CATCH_REQUIRE(c == 33);
118 1 : return true;
119 : }
120 : };
121 :
122 : // Note: you don't usually end up re-using the serializer buffer
123 : // but here it's practical
124 : //
125 1 : buffer.clear();
126 :
127 1 : snapdev::deserializer in(buffer);
128 :
129 : // WARNING: we want to use CATCH_...() macros inside the callback
130 : // so make sure not to use one around unserialize_buffer().
131 : //
132 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
133 2 : &processor::process_hunk
134 : , std::placeholders::_1
135 2 : , std::placeholders::_2));
136 1 : bool const r(in.deserialize(func));
137 1 : CATCH_REQUIRE(r);
138 1 : }
139 13 : CATCH_END_SECTION()
140 :
141 13 : CATCH_START_SECTION("brs: push/restore signed char")
142 : {
143 1 : std::stringstream buffer;
144 1 : snapdev::serializer out(buffer);
145 :
146 1 : std::string data(buffer.str());
147 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
148 :
149 1 : CATCH_REQUIRE(data[0] == 'B');
150 1 : CATCH_REQUIRE(data[1] == 'R');
151 1 : CATCH_REQUIRE(data[2] == 'L');
152 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
153 :
154 1 : signed char value = -43;
155 1 : out.add_value("orange", value);
156 :
157 : // make sure it did not get smashed
158 1 : data = buffer.str();
159 1 : CATCH_REQUIRE(data[0] == 'B');
160 1 : CATCH_REQUIRE(data[1] == 'R');
161 1 : CATCH_REQUIRE(data[2] == 'L');
162 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
163 :
164 1 : CATCH_REQUIRE(data[4] == 6 << 2); // hunk_sizes_t
165 1 : CATCH_REQUIRE(data[5] == 1 << 1);
166 1 : CATCH_REQUIRE(data[6] == 0);
167 1 : CATCH_REQUIRE(data[7] == 0);
168 :
169 1 : CATCH_REQUIRE(data[8] == 'o'); // name
170 1 : CATCH_REQUIRE(data[9] == 'r');
171 1 : CATCH_REQUIRE(data[10] == 'a');
172 1 : CATCH_REQUIRE(data[11] == 'n');
173 1 : CATCH_REQUIRE(data[12] == 'g');
174 1 : CATCH_REQUIRE(data[13] == 'e');
175 :
176 1 : CATCH_REQUIRE(static_cast<signed char>(data[14]) == -43); // value
177 :
178 : struct processor
179 : {
180 1 : static bool process_hunk(
181 : snapdev::deserializer<std::stringstream> & in
182 : , snapdev::field_t const & field)
183 : {
184 1 : CATCH_REQUIRE(field.f_name == "orange");
185 1 : CATCH_REQUIRE(field.f_sub_name.empty());
186 1 : CATCH_REQUIRE(field.f_index == -1);
187 1 : CATCH_REQUIRE(field.f_size == 1);
188 1 : signed char c;
189 1 : in.read_data(c);
190 1 : CATCH_REQUIRE(c == -43);
191 1 : return true;
192 : }
193 : };
194 :
195 : // Note: you don't usually end up re-using the serializer buffer
196 : // but here it's practical
197 : //
198 1 : buffer.clear();
199 :
200 1 : snapdev::deserializer in(buffer);
201 :
202 : // WARNING: we want to use CATCH_...() macros inside the callback
203 : // so make sure not to use one around unserialize_buffer().
204 : //
205 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
206 2 : &processor::process_hunk
207 : , std::placeholders::_1
208 2 : , std::placeholders::_2));
209 1 : bool const r(in.deserialize(func));
210 1 : CATCH_REQUIRE(r);
211 1 : }
212 13 : CATCH_END_SECTION()
213 :
214 13 : CATCH_START_SECTION("brs: push/restore unsigned char")
215 : {
216 1 : std::stringstream buffer;
217 1 : snapdev::serializer out(buffer);
218 :
219 1 : std::string data(buffer.str());
220 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
221 :
222 1 : CATCH_REQUIRE(data[0] == 'B');
223 1 : CATCH_REQUIRE(data[1] == 'R');
224 1 : CATCH_REQUIRE(data[2] == 'L');
225 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
226 :
227 1 : unsigned char value = 200;
228 1 : out.add_value("orange", value);
229 :
230 : // make sure it did not get smashed
231 1 : data = buffer.str();
232 1 : CATCH_REQUIRE(data[0] == 'B');
233 1 : CATCH_REQUIRE(data[1] == 'R');
234 1 : CATCH_REQUIRE(data[2] == 'L');
235 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
236 :
237 1 : CATCH_REQUIRE(data[4] == 6 << 2); // hunk_sizes_t
238 1 : CATCH_REQUIRE(data[5] == 1 << 1);
239 1 : CATCH_REQUIRE(data[6] == 0);
240 1 : CATCH_REQUIRE(data[7] == 0);
241 :
242 1 : CATCH_REQUIRE(data[8] == 'o'); // name
243 1 : CATCH_REQUIRE(data[9] == 'r');
244 1 : CATCH_REQUIRE(data[10] == 'a');
245 1 : CATCH_REQUIRE(data[11] == 'n');
246 1 : CATCH_REQUIRE(data[12] == 'g');
247 1 : CATCH_REQUIRE(data[13] == 'e');
248 :
249 1 : CATCH_REQUIRE(static_cast<unsigned char>(data[14]) == 200); // value
250 :
251 : struct processor
252 : {
253 1 : static bool process_hunk(
254 : snapdev::deserializer<std::stringstream> & in
255 : , snapdev::field_t const & field)
256 : {
257 1 : CATCH_REQUIRE(field.f_name == "orange");
258 1 : CATCH_REQUIRE(field.f_sub_name.empty());
259 1 : CATCH_REQUIRE(field.f_index == -1);
260 1 : CATCH_REQUIRE(field.f_size == 1);
261 1 : unsigned char c;
262 1 : in.read_data(c);
263 1 : CATCH_REQUIRE(c == 200);
264 1 : return true;
265 : }
266 : };
267 :
268 : // Note: you don't usually end up re-using the serializer buffer
269 : // but here it's practical
270 : //
271 1 : buffer.clear();
272 :
273 1 : snapdev::deserializer in(buffer);
274 :
275 : // WARNING: we want to use CATCH_...() macros inside the callback
276 : // so make sure not to use one around unserialize_buffer().
277 : //
278 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
279 2 : &processor::process_hunk
280 : , std::placeholders::_1
281 2 : , std::placeholders::_2));
282 1 : bool const r(in.deserialize(func));
283 1 : CATCH_REQUIRE(r);
284 1 : }
285 13 : CATCH_END_SECTION()
286 :
287 13 : CATCH_START_SECTION("brs: push/restore shorts (16 bits)")
288 : {
289 1 : std::stringstream buffer;
290 1 : snapdev::serializer out(buffer);
291 :
292 1 : std::string data(buffer.str());
293 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
294 :
295 1 : CATCH_REQUIRE(data[0] == 'B');
296 1 : CATCH_REQUIRE(data[1] == 'R');
297 1 : CATCH_REQUIRE(data[2] == 'L');
298 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
299 :
300 1 : std::int16_t const purple = 3003;
301 1 : out.add_value("purple", purple);
302 :
303 1 : std::uint16_t const black = 65001;
304 1 : out.add_value("black", black);
305 :
306 : // make sure it did not get smashed
307 1 : data = buffer.str();
308 1 : CATCH_REQUIRE(data[0] == 'B');
309 1 : CATCH_REQUIRE(data[1] == 'R');
310 1 : CATCH_REQUIRE(data[2] == 'L');
311 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
312 :
313 1 : CATCH_REQUIRE(data[4] == 6 << 2); // hunk_sizes_t
314 1 : CATCH_REQUIRE(data[5] == 2 << 1);
315 1 : CATCH_REQUIRE(data[6] == 0);
316 1 : CATCH_REQUIRE(data[7] == 0);
317 :
318 1 : CATCH_REQUIRE(data[8] == 'p'); // name
319 1 : CATCH_REQUIRE(data[9] == 'u');
320 1 : CATCH_REQUIRE(data[10] == 'r');
321 1 : CATCH_REQUIRE(data[11] == 'p');
322 1 : CATCH_REQUIRE(data[12] == 'l');
323 1 : CATCH_REQUIRE(data[13] == 'e');
324 :
325 : #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
326 : CATCH_REQUIRE(static_cast<std::uint8_t>(data[14]) * 256 + static_cast<std::uint8_t>(data[15]) == 3003); // value
327 : #else
328 1 : CATCH_REQUIRE(static_cast<std::uint8_t>(data[14]) + static_cast<std::uint8_t>(data[15]) * 256 == 3003); // value
329 : #endif
330 :
331 : struct processor
332 : {
333 2 : static bool process_hunk(
334 : snapdev::deserializer<std::stringstream> & in
335 : , snapdev::field_t const & field
336 : , std::int16_t purple
337 : , std::uint16_t black)
338 : {
339 2 : CATCH_REQUIRE(field.f_sub_name.empty());
340 2 : CATCH_REQUIRE(field.f_index == -1);
341 2 : CATCH_REQUIRE(field.f_size == 2);
342 2 : if(field.f_name == "purple")
343 : {
344 1 : std::int16_t value;
345 1 : in.read_data(value);
346 1 : CATCH_REQUIRE(value == purple);
347 : }
348 1 : else if(field.f_name == "black")
349 : {
350 1 : std::uint16_t value;
351 1 : in.read_data(value);
352 1 : CATCH_REQUIRE(value == black);
353 : }
354 : else
355 : {
356 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
357 : }
358 2 : return true;
359 : }
360 : };
361 :
362 : // Note: you don't usually end up re-using the serializer buffer
363 : // but here it's practical
364 : //
365 1 : buffer.clear();
366 :
367 1 : snapdev::deserializer in(buffer);
368 :
369 : // WARNING: we want to use CATCH_...() macros inside the callback
370 : // so make sure not to use one around unserialize_buffer().
371 : //
372 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
373 2 : &processor::process_hunk
374 : , std::placeholders::_1
375 : , std::placeholders::_2
376 : , purple
377 2 : , black));
378 1 : bool const r(in.deserialize(func));
379 1 : CATCH_REQUIRE(r);
380 1 : }
381 13 : CATCH_END_SECTION()
382 :
383 13 : CATCH_START_SECTION("brs: push/restore ints (32 bits)")
384 : {
385 1 : std::stringstream buffer;
386 1 : snapdev::serializer out(buffer);
387 :
388 1 : std::string data(buffer.str());
389 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
390 :
391 1 : CATCH_REQUIRE(data[0] == 'B');
392 1 : CATCH_REQUIRE(data[1] == 'R');
393 1 : CATCH_REQUIRE(data[2] == 'L');
394 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
395 :
396 1 : std::int32_t const red = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
397 1 : out.add_value("red", red);
398 :
399 1 : std::uint32_t const blue = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
400 1 : out.add_value("blue", blue);
401 :
402 : // make sure it did not get smashed
403 1 : data = buffer.str();
404 1 : CATCH_REQUIRE(data[0] == 'B');
405 1 : CATCH_REQUIRE(data[1] == 'R');
406 1 : CATCH_REQUIRE(data[2] == 'L');
407 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
408 :
409 1 : CATCH_REQUIRE(data[4] == 3 << 2); // hunk_sizes_t
410 1 : CATCH_REQUIRE(data[5] == 4 << 1);
411 1 : CATCH_REQUIRE(data[6] == 0);
412 1 : CATCH_REQUIRE(data[7] == 0);
413 :
414 1 : CATCH_REQUIRE(data[8] == 'r'); // name
415 1 : CATCH_REQUIRE(data[9] == 'e');
416 1 : CATCH_REQUIRE(data[10] == 'd');
417 :
418 : #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
419 : CATCH_REQUIRE(
420 : static_cast<std::uint8_t>(data[11]) * 0x1000000
421 : + static_cast<std::uint8_t>(data[12]) * 0x10000
422 : + static_cast<std::uint8_t>(data[13]) * 0x100
423 : + static_cast<std::uint8_t>(data[14]) * 0x1 == red); // value
424 : #else
425 1 : CATCH_REQUIRE(
426 : static_cast<std::uint8_t>(data[14]) * 0x1000000
427 : + static_cast<std::uint8_t>(data[13]) * 0x10000
428 : + static_cast<std::uint8_t>(data[12]) * 0x100
429 : + static_cast<std::uint8_t>(data[11]) * 0x1 == red); // value
430 : #endif
431 :
432 : struct processor
433 : {
434 2 : static bool process_hunk(
435 : snapdev::deserializer<std::stringstream> & in
436 : , snapdev::field_t const & field
437 : , std::int32_t red
438 : , std::uint32_t blue)
439 : {
440 2 : CATCH_REQUIRE(field.f_sub_name.empty());
441 2 : CATCH_REQUIRE(field.f_index == -1);
442 2 : CATCH_REQUIRE(field.f_size == 4);
443 2 : if(field.f_name == "red")
444 : {
445 1 : std::int32_t value;
446 1 : in.read_data(value);
447 1 : CATCH_REQUIRE(value == red);
448 : }
449 1 : else if(field.f_name == "blue")
450 : {
451 1 : std::uint32_t value;
452 1 : in.read_data(value);
453 1 : CATCH_REQUIRE(value == blue);
454 : }
455 : else
456 : {
457 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
458 : }
459 2 : return true;
460 : }
461 : };
462 :
463 : // Note: you don't usually end up re-using the serializer buffer
464 : // but here it's practical
465 : //
466 1 : buffer.clear();
467 :
468 1 : snapdev::deserializer in(buffer);
469 :
470 : // WARNING: we want to use CATCH_...() macros inside the callback
471 : // so make sure not to use one around unserialize_buffer().
472 : //
473 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
474 2 : &processor::process_hunk
475 : , std::placeholders::_1
476 : , std::placeholders::_2
477 : , red
478 2 : , blue));
479 1 : bool const r(in.deserialize(func));
480 1 : CATCH_REQUIRE(r);
481 1 : }
482 13 : CATCH_END_SECTION()
483 :
484 13 : CATCH_START_SECTION("brs: push/restore ints (64 bits)")
485 : {
486 1 : std::stringstream buffer;
487 1 : snapdev::serializer out(buffer);
488 :
489 1 : std::string data(buffer.str());
490 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
491 :
492 1 : CATCH_REQUIRE(data[0] == 'B');
493 1 : CATCH_REQUIRE(data[1] == 'R');
494 1 : CATCH_REQUIRE(data[2] == 'L');
495 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
496 :
497 1 : std::int64_t const white = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
498 1 : out.add_value("white", white);
499 :
500 1 : std::uint64_t const gray = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
501 1 : out.add_value("gray", gray);
502 :
503 : // make sure it did not get smashed
504 1 : data = buffer.str();
505 1 : CATCH_REQUIRE(data[0] == 'B');
506 1 : CATCH_REQUIRE(data[1] == 'R');
507 1 : CATCH_REQUIRE(data[2] == 'L');
508 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
509 :
510 1 : CATCH_REQUIRE(data[4] == 5 << 2); // hunk_sizes_t
511 1 : CATCH_REQUIRE(data[5] == 8 << 1);
512 1 : CATCH_REQUIRE(data[6] == 0);
513 1 : CATCH_REQUIRE(data[7] == 0);
514 :
515 1 : CATCH_REQUIRE(data[8] == 'w'); // name
516 1 : CATCH_REQUIRE(data[9] == 'h');
517 1 : CATCH_REQUIRE(data[10] == 'i');
518 1 : CATCH_REQUIRE(data[11] == 't');
519 1 : CATCH_REQUIRE(data[12] == 'e');
520 :
521 : struct processor
522 : {
523 2 : static bool process_hunk(
524 : snapdev::deserializer<std::stringstream> & in
525 : , snapdev::field_t const & field
526 : , std::int64_t white
527 : , std::uint64_t gray)
528 : {
529 2 : CATCH_REQUIRE(field.f_sub_name.empty());
530 2 : CATCH_REQUIRE(field.f_index == -1);
531 2 : CATCH_REQUIRE(field.f_size == 8);
532 2 : if(field.f_name == "white")
533 : {
534 1 : std::int64_t value;
535 1 : in.read_data(value);
536 1 : CATCH_REQUIRE(value == white);
537 : }
538 1 : else if(field.f_name == "gray")
539 : {
540 1 : std::uint64_t value;
541 1 : in.read_data(value);
542 1 : CATCH_REQUIRE(value == gray);
543 : }
544 : else
545 : {
546 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
547 : }
548 2 : return true;
549 : }
550 : };
551 :
552 : // Note: you don't usually end up re-using the serializer buffer
553 : // but here it's practical
554 : //
555 1 : buffer.clear();
556 :
557 1 : snapdev::deserializer in(buffer);
558 :
559 : // WARNING: we want to use CATCH_...() macros inside the callback
560 : // so make sure not to use one around unserialize_buffer().
561 : //
562 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
563 2 : &processor::process_hunk
564 : , std::placeholders::_1
565 : , std::placeholders::_2
566 : , white
567 2 : , gray));
568 1 : bool const r(in.deserialize(func));
569 1 : CATCH_REQUIRE(r);
570 1 : }
571 13 : CATCH_END_SECTION()
572 :
573 13 : CATCH_START_SECTION("brs: push/restore floats")
574 : {
575 1 : std::stringstream buffer;
576 1 : snapdev::serializer out(buffer);
577 :
578 1 : std::string data(buffer.str());
579 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
580 :
581 1 : CATCH_REQUIRE(data[0] == 'B');
582 1 : CATCH_REQUIRE(data[1] == 'R');
583 1 : CATCH_REQUIRE(data[2] == 'L');
584 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
585 :
586 1 : float const green = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
587 1 : / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
588 1 : out.add_value("green", green);
589 :
590 1 : double const yellow = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
591 1 : / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
592 1 : out.add_value("yellow", yellow);
593 :
594 1 : long double const fushia = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
595 1 : / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
596 1 : out.add_value("fushia", fushia);
597 :
598 : // make sure it did not get smashed
599 1 : data = buffer.str();
600 1 : CATCH_REQUIRE(data[0] == 'B');
601 1 : CATCH_REQUIRE(data[1] == 'R');
602 1 : CATCH_REQUIRE(data[2] == 'L');
603 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
604 :
605 1 : CATCH_REQUIRE(data[4] == 5 << 2); // hunk_sizes_t
606 1 : CATCH_REQUIRE(data[5] == 4 << 1);
607 1 : CATCH_REQUIRE(data[6] == 0);
608 1 : CATCH_REQUIRE(data[7] == 0);
609 :
610 1 : CATCH_REQUIRE(data[8] == 'g'); // name
611 1 : CATCH_REQUIRE(data[9] == 'r');
612 1 : CATCH_REQUIRE(data[10] == 'e');
613 1 : CATCH_REQUIRE(data[11] == 'e');
614 1 : CATCH_REQUIRE(data[12] == 'n');
615 :
616 : struct processor
617 : {
618 3 : static bool process_hunk(
619 : snapdev::deserializer<std::stringstream> & in
620 : , snapdev::field_t const & field
621 : , float green
622 : , double yellow
623 : , long double fushia)
624 : {
625 3 : CATCH_REQUIRE(field.f_sub_name.empty());
626 3 : CATCH_REQUIRE(field.f_index == -1);
627 3 : if(field.f_name == "green")
628 : {
629 1 : CATCH_REQUIRE(field.f_size == 4);
630 :
631 1 : float value;
632 1 : in.read_data(value);
633 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, green, 0.0f));
634 : }
635 2 : else if(field.f_name == "yellow")
636 : {
637 1 : CATCH_REQUIRE(field.f_size == 8);
638 :
639 1 : double value;
640 1 : in.read_data(value);
641 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, yellow, 0.0));
642 : }
643 1 : else if(field.f_name == "fushia")
644 : {
645 1 : CATCH_REQUIRE(field.f_size == 16);
646 :
647 1 : long double value;
648 1 : in.read_data(value);
649 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, fushia, 0.0L));
650 : }
651 : else
652 : {
653 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
654 : }
655 3 : return true;
656 : }
657 : };
658 :
659 : // Note: you don't usually end up re-using the serializer buffer
660 : // but here it's practical
661 : //
662 1 : buffer.clear();
663 :
664 1 : snapdev::deserializer in(buffer);
665 :
666 : // WARNING: we want to use CATCH_...() macros inside the callback
667 : // so make sure not to use one around unserialize_buffer().
668 : //
669 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
670 2 : &processor::process_hunk
671 : , std::placeholders::_1
672 : , std::placeholders::_2
673 : , green
674 : , yellow
675 2 : , fushia));
676 1 : bool const r(in.deserialize(func));
677 1 : CATCH_REQUIRE(r);
678 1 : }
679 13 : CATCH_END_SECTION()
680 :
681 13 : CATCH_START_SECTION("brs: push/restore string")
682 : {
683 1 : std::stringstream buffer;
684 1 : snapdev::serializer out(buffer);
685 :
686 1 : std::string data(buffer.str());
687 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
688 :
689 1 : CATCH_REQUIRE(data[0] == 'B');
690 1 : CATCH_REQUIRE(data[1] == 'R');
691 1 : CATCH_REQUIRE(data[2] == 'L');
692 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
693 :
694 2 : std::string message("this is the message we are going to serialize");
695 1 : out.add_value("message", message);
696 :
697 : // make sure it did not get smashed
698 1 : data = buffer.str();
699 1 : CATCH_REQUIRE(data[0] == 'B');
700 1 : CATCH_REQUIRE(data[1] == 'R');
701 1 : CATCH_REQUIRE(data[2] == 'L');
702 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
703 :
704 1 : CATCH_REQUIRE(data[4] == 7 << 2); // hunk_sizes_t
705 1 : CATCH_REQUIRE(data[5] == 45 << 1);
706 1 : CATCH_REQUIRE(data[6] == 0);
707 1 : CATCH_REQUIRE(data[7] == 0);
708 :
709 1 : CATCH_REQUIRE(data[8] == 'm'); // name
710 1 : CATCH_REQUIRE(data[9] == 'e');
711 1 : CATCH_REQUIRE(data[10] == 's');
712 1 : CATCH_REQUIRE(data[11] == 's');
713 1 : CATCH_REQUIRE(data[12] == 'a');
714 1 : CATCH_REQUIRE(data[13] == 'g');
715 1 : CATCH_REQUIRE(data[14] == 'e');
716 :
717 : struct processor
718 : {
719 1 : static bool process_hunk(
720 : snapdev::deserializer<std::stringstream> & in
721 : , snapdev::field_t const & field
722 : , std::string message)
723 : {
724 1 : CATCH_REQUIRE(field.f_name == "message");
725 1 : CATCH_REQUIRE(field.f_sub_name.empty());
726 1 : CATCH_REQUIRE(field.f_index == -1);
727 1 : CATCH_REQUIRE(field.f_size == 45);
728 :
729 1 : std::string value;
730 1 : in.read_data(value);
731 1 : CATCH_REQUIRE(value == message);
732 :
733 1 : return true;
734 1 : }
735 : };
736 :
737 : // Note: you don't usually end up re-using the serializer buffer
738 : // but here it's practical
739 : //
740 1 : buffer.clear();
741 :
742 1 : snapdev::deserializer in(buffer);
743 :
744 : // WARNING: we want to use CATCH_...() macros inside the callback
745 : // so make sure not to use one around unserialize_buffer().
746 : //
747 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
748 2 : &processor::process_hunk
749 : , std::placeholders::_1
750 : , std::placeholders::_2
751 2 : , message));
752 1 : bool const r(in.deserialize(func));
753 1 : CATCH_REQUIRE(r);
754 1 : }
755 13 : CATCH_END_SECTION()
756 :
757 13 : CATCH_START_SECTION("brs: push/restore array (varying name)")
758 : {
759 1 : std::stringstream buffer;
760 1 : snapdev::serializer out(buffer);
761 :
762 1 : std::string data(buffer.str());
763 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
764 :
765 1 : CATCH_REQUIRE(data[0] == 'B');
766 1 : CATCH_REQUIRE(data[1] == 'R');
767 1 : CATCH_REQUIRE(data[2] == 'L');
768 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
769 :
770 1 : std::vector<int> order;
771 : typedef std::map<int, std::string> value_t;
772 1 : value_t values;
773 1 : int index(-1);
774 26 : for(int i(0); i < 25; ++i)
775 : {
776 : for(;;)
777 : {
778 28 : index = rand() % 256;
779 28 : if(values.find(index) == values.end())
780 : {
781 25 : break;
782 : }
783 : }
784 25 : std::string str;
785 25 : int max(rand() % 25 + 1);
786 310 : for(int j(0); j < max; ++j)
787 : {
788 285 : str += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
789 : }
790 25 : values[index] = str;
791 25 : order.push_back(index);
792 :
793 25 : out.add_value("str" + std::to_string(index), index, str);
794 25 : }
795 :
796 : // make sure it did not get smashed
797 1 : data = buffer.str();
798 1 : CATCH_REQUIRE(data[0] == 'B');
799 1 : CATCH_REQUIRE(data[1] == 'R');
800 1 : CATCH_REQUIRE(data[2] == 'L');
801 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
802 :
803 : struct processor
804 : {
805 25 : static bool process_hunk(
806 : snapdev::deserializer<std::stringstream> & in
807 : , snapdev::field_t const & field
808 : , value_t & values)
809 : {
810 25 : CATCH_REQUIRE(field.f_sub_name.empty());
811 25 : CATCH_REQUIRE(field.f_index != -1);
812 :
813 50 : std::string expected_name("str" + std::to_string(field.f_index));
814 25 : CATCH_REQUIRE(field.f_name == expected_name);
815 :
816 25 : CATCH_REQUIRE(field.f_size == values[field.f_index].length());
817 :
818 25 : std::string value;
819 25 : in.read_data(value);
820 25 : CATCH_REQUIRE(value == values[field.f_index]);
821 :
822 25 : return true;
823 25 : }
824 : };
825 :
826 : // Note: you don't usually end up re-using the serializer buffer
827 : // but here it's practical
828 : //
829 1 : buffer.clear();
830 :
831 1 : snapdev::deserializer in(buffer);
832 :
833 : // WARNING: we want to use CATCH_...() macros inside the callback
834 : // so make sure not to use one around unserialize_buffer().
835 : //
836 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
837 2 : &processor::process_hunk
838 : , std::placeholders::_1
839 : , std::placeholders::_2
840 2 : , values));
841 1 : bool const r(in.deserialize(func));
842 1 : CATCH_REQUIRE(r);
843 1 : }
844 13 : CATCH_END_SECTION()
845 :
846 13 : CATCH_START_SECTION("brs: push/restore array (same name)")
847 : {
848 1 : std::stringstream buffer;
849 1 : snapdev::serializer out(buffer);
850 :
851 1 : std::string data(buffer.str());
852 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
853 :
854 1 : CATCH_REQUIRE(data[0] == 'B');
855 1 : CATCH_REQUIRE(data[1] == 'R');
856 1 : CATCH_REQUIRE(data[2] == 'L');
857 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
858 :
859 : // order does not matter and we can have gaps, to test that, create
860 : // a map of a few values and corresponding strings
861 : //
862 1 : std::vector<int> order;
863 : typedef std::map<int, std::string> value_t;
864 1 : value_t values;
865 1 : int index(-1);
866 1 : int const size(25);
867 26 : for(int i(0); i < size; ++i)
868 : {
869 : for(;;)
870 : {
871 26 : index = rand() % 256;
872 26 : if(values.find(index) == values.end())
873 : {
874 25 : break;
875 : }
876 : }
877 25 : std::string str;
878 25 : int max(rand() % 25 + 1);
879 322 : for(int j(0); j < max; ++j)
880 : {
881 297 : str += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
882 : }
883 25 : values[index] = str;
884 25 : order.push_back(index);
885 :
886 25 : if((index & 1) != 0)
887 : {
888 : // pass as a 'char const *'
889 13 : out.add_value("unique", index, str.c_str());
890 : }
891 : else
892 : {
893 : // pass as an std::string
894 12 : out.add_value("unique", index, str);
895 : }
896 :
897 : // nullptr does nothing
898 25 : out.add_value("unique", index + size, nullptr);
899 25 : }
900 :
901 : // make sure it did not get smashed
902 1 : data = buffer.str();
903 1 : CATCH_REQUIRE(data[0] == 'B');
904 1 : CATCH_REQUIRE(data[1] == 'R');
905 1 : CATCH_REQUIRE(data[2] == 'L');
906 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
907 :
908 : struct processor
909 : {
910 25 : static bool process_hunk(
911 : snapdev::deserializer<std::stringstream> & in
912 : , snapdev::field_t const & field
913 : , value_t & values)
914 : {
915 25 : CATCH_REQUIRE(field.f_name == "unique");
916 25 : CATCH_REQUIRE(field.f_sub_name.empty());
917 25 : CATCH_REQUIRE(field.f_index != -1);
918 :
919 25 : CATCH_REQUIRE(field.f_size == values[field.f_index].length());
920 :
921 25 : std::string value;
922 25 : in.read_data(value);
923 25 : CATCH_REQUIRE(value == values[field.f_index]);
924 :
925 25 : return true;
926 25 : }
927 : };
928 :
929 : // Note: you don't usually end up re-using the serializer buffer
930 : // but here it's practical
931 : //
932 1 : buffer.clear();
933 :
934 1 : snapdev::deserializer in(buffer);
935 :
936 : // WARNING: we want to use CATCH_...() macros inside the callback
937 : // so make sure not to use one around unserialize_buffer().
938 : //
939 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
940 2 : &processor::process_hunk
941 : , std::placeholders::_1
942 : , std::placeholders::_2
943 2 : , values));
944 1 : bool const r(in.deserialize(func));
945 1 : CATCH_REQUIRE(r);
946 1 : }
947 13 : CATCH_END_SECTION()
948 :
949 13 : CATCH_START_SECTION("brs: push/restore map of strings")
950 : {
951 1 : std::stringstream buffer;
952 1 : snapdev::serializer out(buffer);
953 :
954 1 : std::string data(buffer.str());
955 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
956 :
957 1 : CATCH_REQUIRE(data[0] == 'B');
958 1 : CATCH_REQUIRE(data[1] == 'R');
959 1 : CATCH_REQUIRE(data[2] == 'L');
960 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
961 :
962 : // order does not matter and we can have gaps, to test that, create
963 : // a map of a few values and corresponding strings
964 : //
965 1 : std::vector<std::string> order;
966 : typedef std::map<std::string, std::string> value_t;
967 1 : value_t values;
968 1 : int empty(rand() % 25);
969 26 : for(int i(0); i < 25; ++i)
970 : {
971 25 : int max(0);
972 25 : std::string index;
973 : for(;;)
974 : {
975 25 : max = rand() % 25 + 1;
976 347 : for(int j(0); j < max; ++j)
977 : {
978 322 : index += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
979 : }
980 25 : if(values.find(index) == values.end())
981 : {
982 : // index is unique, use it
983 25 : break;
984 : }
985 0 : }
986 :
987 25 : std::string str;
988 25 : if(i != empty)
989 : {
990 24 : max = rand() % 25;
991 267 : for(int j(0); j < max; ++j)
992 : {
993 243 : str += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
994 : }
995 : }
996 :
997 25 : values[index] = str;
998 25 : order.push_back(index);
999 :
1000 25 : if((i & 1) == 0)
1001 : {
1002 13 : if(str.empty()
1003 13 : || (rand() & 1) != 0)
1004 : {
1005 8 : out.add_value("mapping", index, str);
1006 : }
1007 : else
1008 : {
1009 5 : out.add_value_if_not_empty("mapping", index, str);
1010 : }
1011 : }
1012 : else
1013 : {
1014 : // bare string
1015 : //
1016 12 : out.add_value("mapping", index, str.c_str());
1017 : }
1018 :
1019 25 : out.add_value("mapping", index + "a", nullptr);
1020 25 : }
1021 1 : out.add_value_if_not_empty("mapping", "last-index", std::string());
1022 :
1023 : //{
1024 : //std::ofstream p("t1.txt");
1025 : //std::string s(buffer.str());
1026 : //p << s;
1027 : //}
1028 :
1029 : // make sure it did not get smashed
1030 1 : data = buffer.str();
1031 1 : CATCH_REQUIRE(data[0] == 'B');
1032 1 : CATCH_REQUIRE(data[1] == 'R');
1033 1 : CATCH_REQUIRE(data[2] == 'L');
1034 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1035 :
1036 : struct processor
1037 : {
1038 25 : static bool process_hunk(
1039 : snapdev::deserializer<std::stringstream> & in
1040 : , snapdev::field_t const & field
1041 : , value_t & values)
1042 : {
1043 25 : CATCH_REQUIRE(field.f_name == "mapping");
1044 25 : CATCH_REQUIRE_FALSE(field.f_sub_name.empty());
1045 25 : CATCH_REQUIRE(field.f_index == -1);
1046 25 : CATCH_REQUIRE(values.find(field.f_sub_name) != values.end());
1047 :
1048 25 : CATCH_REQUIRE(field.f_size == values[field.f_sub_name].length());
1049 :
1050 25 : std::string value;
1051 25 : in.read_data(value);
1052 25 : CATCH_REQUIRE(value == values[field.f_sub_name]);
1053 :
1054 25 : return true;
1055 25 : }
1056 : };
1057 :
1058 : // Note: you don't usually end up re-using the serializer buffer
1059 : // but here it's practical
1060 : //
1061 1 : buffer.clear();
1062 :
1063 1 : snapdev::deserializer in(buffer);
1064 :
1065 : // WARNING: we want to use CATCH_...() macros inside the callback
1066 : // so make sure not to use one around unserialize_buffer().
1067 : //
1068 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1069 2 : &processor::process_hunk
1070 : , std::placeholders::_1
1071 : , std::placeholders::_2
1072 2 : , values));
1073 1 : bool const r(in.deserialize(func));
1074 1 : CATCH_REQUIRE(r);
1075 1 : }
1076 13 : CATCH_END_SECTION()
1077 :
1078 13 : CATCH_START_SECTION("brs: push/restore map of struct")
1079 : {
1080 : struct data_t
1081 : {
1082 : std::uint32_t f_color = 0xaa648b;
1083 : float f_height = 1.3f;
1084 : std::uint8_t f_status = 3;
1085 : double f_width = 3.7;
1086 :
1087 90 : bool operator == (data_t const & rhs) const
1088 : {
1089 : #pragma GCC diagnostic push
1090 : #pragma GCC diagnostic ignored "-Wfloat-equal"
1091 90 : return f_color == rhs.f_color
1092 90 : && f_height == rhs.f_height
1093 90 : && f_status == rhs.f_status
1094 180 : && f_width == rhs.f_width;
1095 : #pragma GCC diagnostic pop
1096 : }
1097 : };
1098 :
1099 1 : std::stringstream buffer;
1100 1 : snapdev::serializer out(buffer);
1101 :
1102 1 : std::string data(buffer.str());
1103 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
1104 :
1105 1 : CATCH_REQUIRE(data[0] == 'B');
1106 1 : CATCH_REQUIRE(data[1] == 'R');
1107 1 : CATCH_REQUIRE(data[2] == 'L');
1108 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1109 :
1110 : // order does not matter and we can have gaps, to test that, create
1111 : // a map of a few values and corresponding strings
1112 : //
1113 1 : std::vector<std::string> order;
1114 : typedef std::map<std::string, data_t> value_t;
1115 1 : value_t values;
1116 1 : std::size_t const count(rand() % 100 + 25);
1117 91 : for(std::size_t i(0); i < count; ++i)
1118 : {
1119 90 : std::string index;
1120 : for(;;)
1121 : {
1122 90 : int const max(rand() % 25 + 1);
1123 1296 : for(int j(0); j < max; ++j)
1124 : {
1125 1206 : index += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
1126 : }
1127 90 : if(values.find(index) == values.end())
1128 : {
1129 : // index is unique, use it
1130 90 : break;
1131 : }
1132 0 : }
1133 :
1134 90 : data_t my_data;
1135 90 : my_data.f_color = rand(),
1136 90 : my_data.f_height = rand(),
1137 180 : my_data.f_status = rand(),
1138 90 : my_data.f_width = rand(),
1139 :
1140 90 : values[index] = my_data;
1141 90 : order.push_back(index);
1142 :
1143 90 : out.add_value("set", index, my_data);
1144 90 : }
1145 : //{
1146 : //std::ofstream p("t1.txt");
1147 : //std::string s(buffer.str());
1148 : //p << s;
1149 : //}
1150 :
1151 : // make sure it did not get smashed
1152 1 : data = buffer.str();
1153 1 : CATCH_REQUIRE(data[0] == 'B');
1154 1 : CATCH_REQUIRE(data[1] == 'R');
1155 1 : CATCH_REQUIRE(data[2] == 'L');
1156 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1157 :
1158 : struct processor
1159 : {
1160 90 : static bool process_hunk(
1161 : snapdev::deserializer<std::stringstream> & in
1162 : , snapdev::field_t const & field
1163 : , value_t & values)
1164 : {
1165 90 : CATCH_REQUIRE(field.f_name == "set");
1166 90 : CATCH_REQUIRE_FALSE(field.f_sub_name.empty());
1167 90 : CATCH_REQUIRE(field.f_index == -1);
1168 90 : CATCH_REQUIRE(values.find(field.f_sub_name) != values.end());
1169 :
1170 90 : CATCH_REQUIRE(field.f_size == sizeof(data_t));
1171 :
1172 90 : data_t value;
1173 90 : in.read_data(value);
1174 90 : data_t expected(values[field.f_sub_name]);
1175 90 : CATCH_REQUIRE(value == expected);
1176 :
1177 180 : return true;
1178 : }
1179 : };
1180 :
1181 : // Note: you don't usually end up re-using the serializer buffer
1182 : // but here it's practical
1183 : //
1184 1 : buffer.clear();
1185 :
1186 1 : snapdev::deserializer in(buffer);
1187 :
1188 : // WARNING: we want to use CATCH_...() macros inside the callback
1189 : // so make sure not to use one around unserialize_buffer().
1190 : //
1191 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1192 2 : &processor::process_hunk
1193 : , std::placeholders::_1
1194 : , std::placeholders::_2
1195 2 : , values));
1196 1 : bool const r(in.deserialize(func));
1197 1 : CATCH_REQUIRE(r);
1198 1 : }
1199 13 : CATCH_END_SECTION()
1200 :
1201 13 : CATCH_START_SECTION("brs: push/restore recursive")
1202 : {
1203 : class t1
1204 : {
1205 : public:
1206 6 : void serialize(snapdev::serializer<std::stringstream> & out) const
1207 : {
1208 6 : out.add_value("name", f_name);
1209 6 : }
1210 :
1211 6 : bool process_hunk(
1212 : snapdev::deserializer<std::stringstream> & in
1213 : , snapdev::field_t const & field)
1214 : {
1215 6 : CATCH_REQUIRE(field.f_sub_name.empty());
1216 6 : CATCH_REQUIRE(field.f_index == -1);
1217 :
1218 6 : if(field.f_name == "name")
1219 : {
1220 6 : std::string value;
1221 6 : in.read_data(value);
1222 6 : CATCH_REQUIRE(f_name == value);
1223 6 : }
1224 : else
1225 : {
1226 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
1227 : }
1228 :
1229 6 : return true;
1230 : }
1231 :
1232 6 : void set_name(std::string const & name)
1233 : {
1234 6 : f_name = name;
1235 6 : }
1236 :
1237 : private:
1238 : std::string f_name = "--undefined--";
1239 : };
1240 :
1241 : class t2
1242 : {
1243 : public:
1244 1 : void serialize(snapdev::serializer<std::stringstream> & out) const
1245 : {
1246 11 : for(std::size_t idx(0); idx < std::size(f_sizes); ++idx)
1247 : {
1248 10 : out.add_value("size", idx, f_sizes[idx]);
1249 : }
1250 1 : }
1251 :
1252 10 : bool process_hunk(
1253 : snapdev::deserializer<std::stringstream> & in
1254 : , snapdev::field_t const & field)
1255 : {
1256 10 : if(field.f_name == "size")
1257 : {
1258 10 : CATCH_REQUIRE(static_cast<std::size_t>(field.f_index) < std::size(f_sizes));
1259 :
1260 10 : std::int32_t value;
1261 10 : in.read_data(value);
1262 10 : CATCH_REQUIRE(value == f_sizes[field.f_index]);
1263 : }
1264 : else
1265 : {
1266 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
1267 : }
1268 :
1269 10 : return true;
1270 : }
1271 :
1272 : private:
1273 : std::int32_t f_sizes[10] = {
1274 : rand(), rand(), rand(), rand(), rand(),
1275 : rand(), rand(), rand(), rand(), rand(),
1276 : };
1277 : };
1278 :
1279 : // c includes an array of t1's and one t2
1280 : class c
1281 : {
1282 : public:
1283 1 : c()
1284 1 : {
1285 1 : int const max(rand() % 5 + 3);
1286 7 : for(int idx(0); idx < max; ++idx)
1287 : {
1288 6 : std::string name;
1289 6 : int len(rand() % 25 + 10);
1290 165 : for(int j(0); j < len; ++j)
1291 : {
1292 159 : name += 'a' + rand() % 26;
1293 : }
1294 6 : t1 t;
1295 6 : t.set_name(name);
1296 6 : f_t1.push_back(t);
1297 6 : }
1298 :
1299 1 : int const array_max(rand() % 90 + 10);
1300 60 : for(int idx(0); idx < array_max; ++idx)
1301 : {
1302 59 : float nominator(static_cast<float>(rand()));
1303 59 : float denominator(0.0f);
1304 : #pragma GCC diagnostic push
1305 : #pragma GCC diagnostic ignored "-Wfloat-equal"
1306 118 : while(denominator == 0.0f)
1307 : {
1308 59 : denominator = static_cast<float>(rand());
1309 : }
1310 : #pragma GCC diagnostic pop
1311 59 : f_t3.push_back(nominator / denominator);
1312 : }
1313 1 : }
1314 :
1315 1 : void serialize(snapdev::serializer<std::stringstream> & out) const
1316 : {
1317 1 : out.add_value("count", f_count);
1318 1 : out.add_value("age", f_age);
1319 :
1320 : {
1321 1 : int const max(static_cast<int>(f_t1.size()));
1322 7 : for(int idx(0); idx < max; ++idx)
1323 : {
1324 18 : snapdev::recursive r(out, "t1_array");
1325 6 : f_t1[idx].serialize(out);
1326 6 : }
1327 : }
1328 :
1329 1 : out.add_value("float-array", f_t3);
1330 :
1331 : {
1332 3 : snapdev::recursive r(out, "t2");
1333 1 : f_t2.serialize(out);
1334 1 : }
1335 :
1336 1 : out.add_value("flower-color", std::string("bluish"));
1337 1 : out.add_value("flower-height", std::string()); // unknown
1338 1 : out.add_value_if_not_empty("flower-name", std::string()); // unknown -- not added
1339 :
1340 1 : out.add_value("dog-color", "red");
1341 1 : out.add_value("dog-height", ""); // unknown
1342 1 : out.add_value_if_not_empty("dog-name", ""); // unknown -- not added
1343 1 : out.add_value("dog-nothing", nullptr); // unknown -- not added
1344 1 : out.add_value_if_not_empty("dog-eye-color", "green");
1345 1 : }
1346 :
1347 15 : bool process_hunk(
1348 : snapdev::deserializer<std::stringstream> & in
1349 : , snapdev::field_t const & field)
1350 : {
1351 15 : if(field.f_name == "count")
1352 : {
1353 1 : int value;
1354 1 : in.read_data(value);
1355 1 : CATCH_REQUIRE(f_count == value);
1356 : }
1357 14 : else if(field.f_name == "age")
1358 : {
1359 1 : int value;
1360 1 : in.read_data(value);
1361 1 : CATCH_REQUIRE(f_age == value);
1362 : }
1363 13 : else if(field.f_name == "t1_array")
1364 : {
1365 : // this is a set of sub-classes so we do not have an index
1366 : //
1367 6 : CATCH_REQUIRE(field.f_index == -1);
1368 6 : CATCH_REQUIRE(field.f_sub_name == std::string());
1369 :
1370 : // in a normal implementation, here we would create a new
1371 : // item and append it if the load succeeds; the test will
1372 : // instead verify that the f_t1_index is still valid and
1373 : // test load that next f_t1 object
1374 : //
1375 6 : CATCH_REQUIRE(f_t1_index < f_t1.size());
1376 :
1377 18 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1378 12 : &t1::process_hunk
1379 12 : , &f_t1[f_t1_index]
1380 : , std::placeholders::_1
1381 12 : , std::placeholders::_2));
1382 6 : bool const r(in.deserialize(func));
1383 6 : CATCH_REQUIRE(r);
1384 :
1385 6 : ++f_t1_index;
1386 6 : }
1387 7 : else if(field.f_name == "float-array")
1388 : {
1389 1 : CATCH_REQUIRE(field.f_index == -1);
1390 1 : CATCH_REQUIRE(field.f_sub_name == std::string());
1391 :
1392 1 : std::vector<float> v;
1393 1 : in.read_data(v);
1394 1 : CATCH_REQUIRE(v.size() == f_t3.size());
1395 1 : CATCH_REQUIRE(v == f_t3);
1396 1 : }
1397 6 : else if(field.f_name == "t2")
1398 : {
1399 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1400 2 : &t2::process_hunk
1401 2 : , &f_t2
1402 : , std::placeholders::_1
1403 2 : , std::placeholders::_2));
1404 1 : bool const r(in.deserialize(func));
1405 1 : CATCH_REQUIRE(r);
1406 1 : }
1407 5 : else if(field.f_name == "flower-color")
1408 : {
1409 1 : std::string value;
1410 1 : in.read_data(value);
1411 1 : CATCH_REQUIRE(value.length() == std::string("bluish").length());
1412 1 : CATCH_REQUIRE(value == std::string("bluish"));
1413 1 : }
1414 4 : else if(field.f_name == "flower-height")
1415 : {
1416 1 : std::string value;
1417 1 : in.read_data(value);
1418 1 : CATCH_REQUIRE(value == std::string());
1419 1 : }
1420 3 : else if(field.f_name == "flower-name")
1421 : {
1422 : // this field should not be added since the value is
1423 : // the empty string and we on purpose avoid adding
1424 : // it (i.e. "add value (only) if not empty")
1425 : //
1426 0 : CATCH_REQUIRE(field.f_name == "not-expected");
1427 : }
1428 3 : else if(field.f_name == "dog-color")
1429 : {
1430 1 : std::string value;
1431 1 : in.read_data(value);
1432 1 : CATCH_REQUIRE(value.length() == std::string("red").length());
1433 1 : CATCH_REQUIRE(value == std::string("red"));
1434 1 : }
1435 2 : else if(field.f_name == "dog-height")
1436 : {
1437 1 : std::string value;
1438 1 : in.read_data(value);
1439 1 : CATCH_REQUIRE(value == std::string());
1440 1 : }
1441 1 : else if(field.f_name == "dog-name"
1442 1 : || field.f_name == "dog-nothing")
1443 : {
1444 : // this field should not be added since the value is
1445 : // the empty string and we on purpose avoid adding
1446 : // it (i.e. "add value (only) if not empty")
1447 : //
1448 0 : CATCH_REQUIRE(field.f_name == "not-expected");
1449 : }
1450 1 : else if(field.f_name == "dog-eye-color")
1451 : {
1452 1 : std::string value;
1453 1 : in.read_data(value);
1454 1 : CATCH_REQUIRE(value == std::string("green"));
1455 1 : }
1456 : else
1457 : {
1458 0 : CATCH_REQUIRE(field.f_name == "?unknown?");
1459 : }
1460 :
1461 15 : return true;
1462 : }
1463 :
1464 : private:
1465 : int f_count = rand();
1466 : int f_age = rand() % 100;
1467 : std::vector<t1> f_t1 = std::vector<t1>();
1468 : t2 f_t2 = t2();
1469 : std::vector<float> f_t3 = {};
1470 : std::size_t f_t1_index = 0;
1471 : };
1472 :
1473 1 : c o;
1474 :
1475 1 : std::stringstream buffer;
1476 1 : snapdev::serializer out(buffer);
1477 :
1478 1 : std::string data(buffer.str());
1479 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
1480 :
1481 1 : CATCH_REQUIRE(data[0] == 'B');
1482 1 : CATCH_REQUIRE(data[1] == 'R');
1483 1 : CATCH_REQUIRE(data[2] == 'L');
1484 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1485 :
1486 1 : o.serialize(out);
1487 :
1488 : // Note: you don't usually end up re-using the serializer buffer
1489 : // but here it's practical
1490 : //
1491 1 : buffer.clear();
1492 :
1493 1 : snapdev::deserializer in(buffer);
1494 :
1495 : // WARNING: we want to use CATCH_...() macros inside the callback
1496 : // so make sure not to use one around unserialize_buffer().
1497 : //
1498 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1499 2 : &c::process_hunk
1500 2 : , &o
1501 : , std::placeholders::_1
1502 2 : , std::placeholders::_2));
1503 1 : bool const r(in.deserialize(func));
1504 1 : CATCH_REQUIRE(r);
1505 1 : }
1506 13 : CATCH_END_SECTION()
1507 13 : }
1508 :
1509 :
1510 14 : CATCH_TEST_CASE("brs_invalid", "[serialization][error]")
1511 : {
1512 14 : CATCH_START_SECTION("brs: name missing")
1513 : {
1514 1 : std::stringstream buffer;
1515 1 : snapdev::serializer out(buffer);
1516 :
1517 1 : std::string data(buffer.str());
1518 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
1519 :
1520 1 : CATCH_REQUIRE(data[0] == 'B');
1521 1 : CATCH_REQUIRE(data[1] == 'R');
1522 1 : CATCH_REQUIRE(data[2] == 'L');
1523 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1524 :
1525 1 : char value = 33;
1526 :
1527 : // FIELD
1528 3 : CATCH_REQUIRE_THROWS_MATCHES(
1529 : out.add_value(std::string(), &value, sizeof(value))
1530 : , snapdev::brs_cannot_be_empty
1531 : , Catch::Matchers::ExceptionMessage(
1532 : "brs_error: name cannot be an empty string"));
1533 :
1534 : // ARRAY
1535 3 : CATCH_REQUIRE_THROWS_MATCHES(
1536 : out.add_value(std::string(), 5, &value, sizeof(value))
1537 : , snapdev::brs_cannot_be_empty
1538 : , Catch::Matchers::ExceptionMessage(
1539 : "brs_error: name cannot be an empty string"));
1540 :
1541 : // MAP (main name)
1542 5 : CATCH_REQUIRE_THROWS_MATCHES(
1543 : out.add_value(std::string(), std::string(), &value, sizeof(value))
1544 : , snapdev::brs_cannot_be_empty
1545 : , Catch::Matchers::ExceptionMessage(
1546 : "brs_error: name cannot be an empty string"));
1547 :
1548 : // MAP (sub-name)
1549 7 : CATCH_REQUIRE_THROWS_MATCHES(
1550 : out.add_value("good-name", std::string(), &value, sizeof(value))
1551 : , snapdev::brs_cannot_be_empty
1552 : , Catch::Matchers::ExceptionMessage(
1553 : "brs_error: sub-name cannot be an empty string"));
1554 :
1555 : // SUB-FIELD
1556 3 : CATCH_REQUIRE_THROWS_MATCHES(
1557 : out.start_subfield(std::string())
1558 : , snapdev::brs_cannot_be_empty
1559 : , Catch::Matchers::ExceptionMessage(
1560 : "brs_error: name cannot be an empty string"));
1561 1 : }
1562 14 : CATCH_END_SECTION()
1563 :
1564 14 : CATCH_START_SECTION("brs: name too long")
1565 : {
1566 1 : std::stringstream buffer;
1567 1 : snapdev::serializer out(buffer);
1568 :
1569 1 : std::string data(buffer.str());
1570 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
1571 :
1572 1 : CATCH_REQUIRE(data[0] == 'B');
1573 1 : CATCH_REQUIRE(data[1] == 'R');
1574 1 : CATCH_REQUIRE(data[2] == 'L');
1575 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1576 :
1577 1 : std::string name;
1578 1 : std::size_t count(1 << SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_name));
1579 1 : std::size_t const max(count + rand() % 200);
1580 287 : for(std::size_t idx(0); idx < max; ++idx)
1581 : {
1582 286 : name += rand() % 26 + 'a';
1583 : }
1584 :
1585 1 : char value = 33;
1586 :
1587 : // FIELD
1588 3 : CATCH_REQUIRE_THROWS_MATCHES(
1589 : out.add_value(name, &value, sizeof(value))
1590 : , snapdev::brs_out_of_range
1591 : , Catch::Matchers::ExceptionMessage(
1592 : "brs_out_of_range: name or hunk too large"));
1593 :
1594 : // ARRAY
1595 3 : CATCH_REQUIRE_THROWS_MATCHES(
1596 : out.add_value(name, 17, &value, sizeof(value))
1597 : , snapdev::brs_out_of_range
1598 : , Catch::Matchers::ExceptionMessage(
1599 : "brs_out_of_range: name, index, or hunk too large"));
1600 :
1601 : // MAP (main name)
1602 7 : CATCH_REQUIRE_THROWS_MATCHES(
1603 : out.add_value(name, "name-too-long", &value, sizeof(value))
1604 : , snapdev::brs_out_of_range
1605 : , Catch::Matchers::ExceptionMessage(
1606 : "brs_out_of_range: name, sub-name, or hunk too large"));
1607 :
1608 : // MAP (sub-name)
1609 : //
1610 : // sub-names make use of an std::uint8_t for their size
1611 : //
1612 1 : std::string sub_name;
1613 1 : std::size_t const sub_max(std::numeric_limits<std::uint8_t>::max() + 1 + rand() % 200);
1614 317 : for(std::size_t idx(0); idx < sub_max; ++idx)
1615 : {
1616 316 : sub_name += rand() % 26 + 'a';
1617 : }
1618 :
1619 7 : CATCH_REQUIRE_THROWS_MATCHES(
1620 : out.add_value("sub-name-too-long", sub_name, &value, sizeof(value))
1621 : , snapdev::brs_out_of_range
1622 : , Catch::Matchers::ExceptionMessage(
1623 : "brs_out_of_range: name, sub-name, or hunk too large"));
1624 :
1625 : // SUB-FIELD
1626 3 : CATCH_REQUIRE_THROWS_MATCHES(
1627 : out.start_subfield(name)
1628 : , snapdev::brs_out_of_range
1629 : , Catch::Matchers::ExceptionMessage(
1630 : "brs_out_of_range: name too large"));
1631 1 : }
1632 14 : CATCH_END_SECTION()
1633 :
1634 14 : CATCH_START_SECTION("brs: hunk too long")
1635 : {
1636 1 : std::stringstream buffer;
1637 1 : snapdev::serializer out(buffer);
1638 :
1639 1 : std::string data(buffer.str());
1640 1 : CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
1641 :
1642 1 : CATCH_REQUIRE(data[0] == 'B');
1643 1 : CATCH_REQUIRE(data[1] == 'R');
1644 1 : CATCH_REQUIRE(data[2] == 'L');
1645 1 : CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
1646 :
1647 1 : char value = 33;
1648 11 : for(std::size_t extra(0); extra < 10; ++extra)
1649 : {
1650 300 : CATCH_REQUIRE_THROWS_MATCHES(
1651 : out.add_value("large-hunk", &value, (1 << SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_hunk)) + extra)
1652 : , snapdev::brs_out_of_range
1653 : , Catch::Matchers::ExceptionMessage(
1654 : "brs_out_of_range: name or hunk too large"));
1655 :
1656 300 : CATCH_REQUIRE_THROWS_MATCHES(
1657 : out.add_value("large-hunk", 33, &value, (1 << SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_hunk)) + extra)
1658 : , snapdev::brs_out_of_range
1659 : , Catch::Matchers::ExceptionMessage(
1660 : "brs_out_of_range: name, index, or hunk too large"));
1661 :
1662 340 : CATCH_REQUIRE_THROWS_MATCHES(
1663 : out.add_value("large-hunk", "sub-name", &value, (1 << SIZEOF_BITFIELD(snapdev::hunk_sizes_t, f_hunk)) + extra)
1664 : , snapdev::brs_out_of_range
1665 : , Catch::Matchers::ExceptionMessage(
1666 : "brs_out_of_range: name, sub-name, or hunk too large"));
1667 : }
1668 1 : }
1669 14 : CATCH_END_SECTION()
1670 :
1671 14 : CATCH_START_SECTION("brs: empty input")
1672 : {
1673 1 : std::stringstream buffer;
1674 :
1675 1 : CATCH_REQUIRE_THROWS_MATCHES(
1676 : snapdev::deserializer<std::stringstream>(buffer)
1677 : , snapdev::brs_magic_missing
1678 : , Catch::Matchers::ExceptionMessage(
1679 : "brs_error: magic missing from the start of the buffer."));
1680 1 : }
1681 14 : CATCH_END_SECTION()
1682 :
1683 14 : CATCH_START_SECTION("brs: magic unrecognized")
1684 : {
1685 1 : std::stringstream buffer;
1686 :
1687 1 : buffer << 'G'; // pretend it's a GIF
1688 1 : buffer << 'I';
1689 1 : buffer << 'F';
1690 1 : buffer << '8';
1691 1 : buffer << '9';
1692 1 : buffer << 'a';
1693 :
1694 1 : CATCH_REQUIRE_THROWS_MATCHES(
1695 : snapdev::deserializer<std::stringstream>(buffer)
1696 : , snapdev::brs_magic_unsupported
1697 : , Catch::Matchers::ExceptionMessage(
1698 : "brs_error: magic unsupported."));
1699 1 : }
1700 14 : CATCH_END_SECTION()
1701 :
1702 14 : CATCH_START_SECTION("brs: unknown hunk type")
1703 : {
1704 1 : std::stringstream buffer;
1705 :
1706 : // magic
1707 1 : buffer << 'B';
1708 1 : buffer << 'R';
1709 1 : buffer << 'L';
1710 1 : buffer << snapdev::BRS_VERSION;
1711 :
1712 : // size hunk
1713 : // type 3 is not recognized at the moment
1714 1 : std::uint32_t hunk(static_cast<std::uint32_t>((0x03 << 0) | (3 << 2) | (11 << 9)));
1715 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1716 :
1717 : struct processor
1718 : {
1719 0 : static bool process_hunk(
1720 : snapdev::deserializer<std::stringstream> & in
1721 : , snapdev::field_t const & field)
1722 : {
1723 0 : snapdev::NOT_USED(in, field);
1724 0 : throw std::logic_error("process_hunk() was called!");
1725 : }
1726 : };
1727 :
1728 1 : snapdev::deserializer<std::stringstream> in(buffer);
1729 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1730 2 : &processor::process_hunk
1731 : , std::placeholders::_1
1732 2 : , std::placeholders::_2));
1733 :
1734 1 : CATCH_REQUIRE_THROWS_MATCHES(
1735 : in.deserialize(func)
1736 : , snapdev::brs_unknown_type
1737 : , Catch::Matchers::ExceptionMessage(
1738 : "brs_error: read a field with an unknown type."));
1739 1 : }
1740 14 : CATCH_END_SECTION()
1741 :
1742 14 : CATCH_START_SECTION("brs: field missing name")
1743 : {
1744 1 : std::stringstream buffer;
1745 :
1746 : // magic
1747 1 : buffer << 'B';
1748 1 : buffer << 'R';
1749 1 : buffer << 'L';
1750 1 : buffer << snapdev::BRS_VERSION;
1751 :
1752 : // size hunk
1753 : // type 3 is not recognized at the moment
1754 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_FIELD << 0) | (3 << 2) | (11 << 9)));
1755 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1756 :
1757 : struct processor
1758 : {
1759 0 : static bool process_hunk(
1760 : snapdev::deserializer<std::stringstream> & in
1761 : , snapdev::field_t const & field)
1762 : {
1763 0 : snapdev::NOT_USED(in, field);
1764 0 : throw std::logic_error("process_hunk() was called!");
1765 : }
1766 : };
1767 :
1768 1 : snapdev::deserializer<std::stringstream> in(buffer);
1769 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1770 2 : &processor::process_hunk
1771 : , std::placeholders::_1
1772 2 : , std::placeholders::_2));
1773 :
1774 1 : bool r(in.deserialize(func));
1775 1 : CATCH_REQUIRE_FALSE(r);
1776 1 : }
1777 14 : CATCH_END_SECTION()
1778 :
1779 14 : CATCH_START_SECTION("brs: field data mismatch reading")
1780 : {
1781 1 : std::stringstream buffer;
1782 :
1783 : // magic
1784 1 : buffer << 'B';
1785 1 : buffer << 'R';
1786 1 : buffer << 'L';
1787 1 : buffer << snapdev::BRS_VERSION;
1788 :
1789 : // size hunk
1790 : // type 3 is not recognized at the moment
1791 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_FIELD << 0) | (3 << 2) | (1 << 9)));
1792 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1793 1 : char const * name("ABC");
1794 1 : buffer.write(name, 3);
1795 1 : std::uint8_t value(5);
1796 1 : buffer.write(reinterpret_cast<char const *>(&value), 1);
1797 :
1798 : struct processor
1799 : {
1800 1 : static bool process_hunk(
1801 : snapdev::deserializer<std::stringstream> & in
1802 : , snapdev::field_t const & field)
1803 : {
1804 1 : CATCH_REQUIRE(field.f_name == "ABC");
1805 1 : CATCH_REQUIRE(field.f_sub_name == std::string());
1806 1 : CATCH_REQUIRE(field.f_index == -1);
1807 1 : CATCH_REQUIRE(field.f_size == 1);
1808 :
1809 : // reading the data other than the byte creates errors
1810 : // (incorrect size--so you may be calling the read_data()
1811 : // function with the wrong type)
1812 : //
1813 :
1814 1 : std::int16_t s;
1815 1 : CATCH_REQUIRE_THROWS_MATCHES(
1816 : in.read_data(s)
1817 : , snapdev::brs_logic_error
1818 : , Catch::Matchers::ExceptionMessage(
1819 : "brs_logic_error: hunk size is 1, but you are trying to read 2."));
1820 :
1821 1 : std::uint16_t us;
1822 1 : CATCH_REQUIRE_THROWS_MATCHES(
1823 : in.read_data(us)
1824 : , snapdev::brs_logic_error
1825 : , Catch::Matchers::ExceptionMessage(
1826 : "brs_logic_error: hunk size is 1, but you are trying to read 2."));
1827 :
1828 1 : std::int32_t i;
1829 1 : CATCH_REQUIRE_THROWS_MATCHES(
1830 : in.read_data(i)
1831 : , snapdev::brs_logic_error
1832 : , Catch::Matchers::ExceptionMessage(
1833 : "brs_logic_error: hunk size is 1, but you are trying to read 4."));
1834 :
1835 1 : std::uint32_t ui;
1836 1 : CATCH_REQUIRE_THROWS_MATCHES(
1837 : in.read_data(ui)
1838 : , snapdev::brs_logic_error
1839 : , Catch::Matchers::ExceptionMessage(
1840 : "brs_logic_error: hunk size is 1, but you are trying to read 4."));
1841 :
1842 1 : std::int64_t l;
1843 1 : CATCH_REQUIRE_THROWS_MATCHES(
1844 : in.read_data(l)
1845 : , snapdev::brs_logic_error
1846 : , Catch::Matchers::ExceptionMessage(
1847 : "brs_logic_error: hunk size is 1, but you are trying to read 8."));
1848 :
1849 1 : std::uint64_t ul;
1850 1 : CATCH_REQUIRE_THROWS_MATCHES(
1851 : in.read_data(ul)
1852 : , snapdev::brs_logic_error
1853 : , Catch::Matchers::ExceptionMessage(
1854 : "brs_logic_error: hunk size is 1, but you are trying to read 8."));
1855 :
1856 1 : float f;
1857 1 : CATCH_REQUIRE_THROWS_MATCHES(
1858 : in.read_data(f)
1859 : , snapdev::brs_logic_error
1860 : , Catch::Matchers::ExceptionMessage(
1861 : "brs_logic_error: hunk size is 1, but you are trying to read 4."));
1862 :
1863 1 : double d;
1864 1 : CATCH_REQUIRE_THROWS_MATCHES(
1865 : in.read_data(d)
1866 : , snapdev::brs_logic_error
1867 : , Catch::Matchers::ExceptionMessage(
1868 : "brs_logic_error: hunk size is 1, but you are trying to read 8."));
1869 :
1870 1 : long double ld;
1871 1 : CATCH_REQUIRE_THROWS_MATCHES(
1872 : in.read_data(ld)
1873 : , snapdev::brs_logic_error
1874 : , Catch::Matchers::ExceptionMessage(
1875 : "brs_logic_error: hunk size is 1, but you are trying to read 16."));
1876 :
1877 1 : std::vector<std::int64_t> vl;
1878 1 : CATCH_REQUIRE_THROWS_MATCHES(
1879 : in.read_data(vl)
1880 : , snapdev::brs_logic_error
1881 : , Catch::Matchers::ExceptionMessage(
1882 : "brs_logic_error: hunk size (1) is not a multiple of the vector item size: 8."));
1883 :
1884 1 : std::uint8_t b(0);
1885 1 : CATCH_REQUIRE(in.read_data(b));
1886 1 : CATCH_REQUIRE(b == 5);
1887 :
1888 1 : return true;
1889 1 : }
1890 : };
1891 :
1892 1 : snapdev::deserializer<std::stringstream> in(buffer);
1893 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1894 2 : &processor::process_hunk
1895 : , std::placeholders::_1
1896 2 : , std::placeholders::_2));
1897 :
1898 1 : bool r(in.deserialize(func));
1899 1 : CATCH_REQUIRE(r);
1900 1 : }
1901 14 : CATCH_END_SECTION()
1902 :
1903 14 : CATCH_START_SECTION("brs: missing array index")
1904 : {
1905 1 : std::stringstream buffer;
1906 :
1907 : // magic
1908 1 : buffer << 'B';
1909 1 : buffer << 'R';
1910 1 : buffer << 'L';
1911 1 : buffer << snapdev::BRS_VERSION;
1912 :
1913 : // size hunk
1914 : // type 3 is not recognized at the moment
1915 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_ARRAY << 0) | (3 << 2) | (11 << 9)));
1916 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1917 :
1918 : struct processor
1919 : {
1920 0 : static bool process_hunk(
1921 : snapdev::deserializer<std::stringstream> & in
1922 : , snapdev::field_t const & field)
1923 : {
1924 0 : snapdev::NOT_USED(in, field);
1925 0 : throw std::logic_error("process_hunk() was called!");
1926 : }
1927 : };
1928 :
1929 1 : snapdev::deserializer<std::stringstream> in(buffer);
1930 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1931 2 : &processor::process_hunk
1932 : , std::placeholders::_1
1933 2 : , std::placeholders::_2));
1934 :
1935 1 : bool r(in.deserialize(func));
1936 1 : CATCH_REQUIRE_FALSE(r);
1937 1 : }
1938 14 : CATCH_END_SECTION()
1939 :
1940 14 : CATCH_START_SECTION("brs: missing array field name")
1941 : {
1942 1 : std::stringstream buffer;
1943 :
1944 : // magic
1945 1 : buffer << 'B';
1946 1 : buffer << 'R';
1947 1 : buffer << 'L';
1948 1 : buffer << snapdev::BRS_VERSION;
1949 :
1950 : // size hunk
1951 : // type 3 is not recognized at the moment
1952 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_ARRAY << 0) | (3 << 2) | (11 << 9)));
1953 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1954 1 : std::uint16_t size(10);
1955 1 : buffer.write(reinterpret_cast<char const *>(&size), 2);
1956 :
1957 : struct processor
1958 : {
1959 0 : static bool process_hunk(
1960 : snapdev::deserializer<std::stringstream> & in
1961 : , snapdev::field_t const & field)
1962 : {
1963 0 : snapdev::NOT_USED(in, field);
1964 0 : throw std::logic_error("process_hunk() was called!");
1965 : }
1966 : };
1967 :
1968 1 : snapdev::deserializer<std::stringstream> in(buffer);
1969 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
1970 2 : &processor::process_hunk
1971 : , std::placeholders::_1
1972 2 : , std::placeholders::_2));
1973 :
1974 1 : bool r(in.deserialize(func));
1975 1 : CATCH_REQUIRE_FALSE(r);
1976 1 : }
1977 14 : CATCH_END_SECTION()
1978 :
1979 14 : CATCH_START_SECTION("brs: missing map sub-name length")
1980 : {
1981 1 : std::stringstream buffer;
1982 :
1983 : // magic
1984 1 : buffer << 'B';
1985 1 : buffer << 'R';
1986 1 : buffer << 'L';
1987 1 : buffer << snapdev::BRS_VERSION;
1988 :
1989 : // size hunk
1990 : // type 3 is not recognized at the moment
1991 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_MAP << 0) | (3 << 2) | (11 << 9)));
1992 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
1993 :
1994 : struct processor
1995 : {
1996 0 : static bool process_hunk(
1997 : snapdev::deserializer<std::stringstream> & in
1998 : , snapdev::field_t const & field)
1999 : {
2000 0 : snapdev::NOT_USED(in, field);
2001 0 : throw std::logic_error("process_hunk() was called!");
2002 : }
2003 : };
2004 :
2005 1 : snapdev::deserializer<std::stringstream> in(buffer);
2006 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
2007 2 : &processor::process_hunk
2008 : , std::placeholders::_1
2009 2 : , std::placeholders::_2));
2010 :
2011 1 : bool r(in.deserialize(func));
2012 1 : CATCH_REQUIRE_FALSE(r);
2013 1 : }
2014 14 : CATCH_END_SECTION()
2015 :
2016 14 : CATCH_START_SECTION("brs: map sub-name length is zero")
2017 : {
2018 1 : std::stringstream buffer;
2019 :
2020 : // magic
2021 1 : buffer << 'B';
2022 1 : buffer << 'R';
2023 1 : buffer << 'L';
2024 1 : buffer << snapdev::BRS_VERSION;
2025 :
2026 : // size hunk
2027 : // type 3 is not recognized at the moment
2028 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_MAP << 0) | (3 << 2) | (11 << 9)));
2029 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
2030 1 : std::uint8_t len(0);
2031 1 : buffer.write(reinterpret_cast<char const *>(&len), 1);
2032 :
2033 : struct processor
2034 : {
2035 0 : static bool process_hunk(
2036 : snapdev::deserializer<std::stringstream> & in
2037 : , snapdev::field_t const & field)
2038 : {
2039 0 : snapdev::NOT_USED(in, field);
2040 0 : throw std::logic_error("process_hunk() was called!");
2041 : }
2042 : };
2043 :
2044 1 : snapdev::deserializer<std::stringstream> in(buffer);
2045 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
2046 2 : &processor::process_hunk
2047 : , std::placeholders::_1
2048 2 : , std::placeholders::_2));
2049 :
2050 1 : CATCH_REQUIRE_THROWS_MATCHES(
2051 : in.deserialize(func)
2052 : , snapdev::brs_map_name_cannot_be_empty
2053 : , Catch::Matchers::ExceptionMessage(
2054 : "brs_error: the length of a map's field name cannot be zero."));
2055 1 : }
2056 14 : CATCH_END_SECTION()
2057 :
2058 14 : CATCH_START_SECTION("brs: missing map sub-name")
2059 : {
2060 1 : std::stringstream buffer;
2061 :
2062 : // magic
2063 1 : buffer << 'B';
2064 1 : buffer << 'R';
2065 1 : buffer << 'L';
2066 1 : buffer << snapdev::BRS_VERSION;
2067 :
2068 : // size hunk
2069 : // type 3 is not recognized at the moment
2070 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_MAP << 0) | (3 << 2) | (11 << 9)));
2071 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
2072 1 : std::uint8_t len(10);
2073 1 : buffer.write(reinterpret_cast<char const *>(&len), 1);
2074 :
2075 : struct processor
2076 : {
2077 0 : static bool process_hunk(
2078 : snapdev::deserializer<std::stringstream> & in
2079 : , snapdev::field_t const & field)
2080 : {
2081 0 : snapdev::NOT_USED(in, field);
2082 0 : throw std::logic_error("process_hunk() was called!");
2083 : }
2084 : };
2085 :
2086 1 : snapdev::deserializer<std::stringstream> in(buffer);
2087 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
2088 2 : &processor::process_hunk
2089 : , std::placeholders::_1
2090 2 : , std::placeholders::_2));
2091 :
2092 1 : bool r(in.deserialize(func));
2093 1 : CATCH_REQUIRE_FALSE(r);
2094 1 : }
2095 14 : CATCH_END_SECTION()
2096 :
2097 14 : CATCH_START_SECTION("brs: missing map name")
2098 : {
2099 1 : std::stringstream buffer;
2100 :
2101 : // magic
2102 1 : buffer << 'B';
2103 1 : buffer << 'R';
2104 1 : buffer << 'L';
2105 1 : buffer << snapdev::BRS_VERSION;
2106 :
2107 : // size hunk
2108 : // type 3 is not recognized at the moment
2109 1 : std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_MAP << 0) | (3 << 2) | (11 << 9)));
2110 1 : buffer.write(reinterpret_cast<char const *>(&hunk), 4);
2111 1 : std::uint8_t len(3);
2112 1 : buffer.write(reinterpret_cast<char const *>(&len), 1);
2113 1 : char const * name = "SUB";
2114 1 : buffer.write(name, 3);
2115 :
2116 : struct processor
2117 : {
2118 0 : static bool process_hunk(
2119 : snapdev::deserializer<std::stringstream> & in
2120 : , snapdev::field_t const & field)
2121 : {
2122 0 : snapdev::NOT_USED(in, field);
2123 0 : throw std::logic_error("process_hunk() was called!");
2124 : }
2125 : };
2126 :
2127 1 : snapdev::deserializer<std::stringstream> in(buffer);
2128 3 : snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
2129 2 : &processor::process_hunk
2130 : , std::placeholders::_1
2131 2 : , std::placeholders::_2));
2132 :
2133 1 : bool r(in.deserialize(func));
2134 1 : CATCH_REQUIRE_FALSE(r);
2135 1 : }
2136 14 : CATCH_END_SECTION()
2137 14 : }
2138 :
2139 :
2140 : // vim: ts=4 sw=4 et
|