LCOV - code coverage report
Current view: top level - tests - catch_brs.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 96.7 % 1076 1041
Test Date: 2025-07-03 19:05:49 Functions: 100.0 % 25 25
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2011-2025  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            3 :         out.add_value("orange", value);
      77              : 
      78            5 :         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            3 :         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            3 :         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            3 :         out.add_value("purple", purple);
     302              : 
     303            1 :         std::uint16_t const black = 65001;
     304            3 :         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            3 :         out.add_value("red", red);
     398              : 
     399            1 :         std::uint32_t const blue = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     400            3 :         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            3 :         out.add_value("white", white);
     499              : 
     500            1 :         std::uint64_t const gray = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     501            3 :         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            3 :         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            3 :         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            3 :         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            3 :         std::string message("this is the message we are going to serialize");
     695            3 :         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            4 :         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           25 :                 index = rand() % 256;
     779           25 :                 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          356 :             for(int j(0); j < max; ++j)
     787              :             {
     788          331 :                 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           25 :                 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            4 :         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           25 :                 index = rand() % 256;
     872           25 :                 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          331 :             for(int j(0); j < max; ++j)
     880              :             {
     881          306 :                 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           39 :                 out.add_value("unique", index, str.c_str());
     890              :             }
     891              :             else
     892              :             {
     893              :                 // pass as an std::string
     894           36 :                 out.add_value("unique", index, str);
     895              :             }
     896              : 
     897              :             // nullptr does nothing
     898           75 :             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            4 :         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          323 :                 for(int j(0); j < max; ++j)
     977              :                 {
     978          298 :                     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          309 :                 for(int j(0); j < max; ++j)
     992              :                 {
     993          285 :                     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           15 :                     out.add_value("mapping", index, str);
    1006              :                 }
    1007              :                 else
    1008              :                 {
    1009           24 :                     out.add_value_if_not_empty("mapping", index, str);
    1010              :                 }
    1011              :             }
    1012              :             else
    1013              :             {
    1014              :                 // bare string
    1015              :                 //
    1016           36 :                 out.add_value("mapping", index, str.c_str());
    1017              :             }
    1018              : 
    1019           75 :             out.add_value("mapping", index + "a", nullptr);
    1020           25 :         }
    1021            5 :         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            4 :         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          120 :             bool operator == (data_t const & rhs) const
    1088              :             {
    1089              : #pragma GCC diagnostic push
    1090              : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1091          120 :                 return f_color == rhs.f_color
    1092          120 :                     && f_height == rhs.f_height
    1093          120 :                     && f_status == rhs.f_status
    1094          240 :                     && 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          121 :         for(std::size_t i(0); i < count; ++i)
    1118              :         {
    1119          120 :             std::string index;
    1120              :             for(;;)
    1121              :             {
    1122          120 :                 int const max(rand() % 25 + 1);
    1123         1518 :                 for(int j(0); j < max; ++j)
    1124              :                 {
    1125         1398 :                     index += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
    1126              :                 }
    1127          120 :                 if(values.find(index) == values.end())
    1128              :                 {
    1129              :                     // index is unique, use it
    1130          120 :                     break;
    1131              :                 }
    1132            0 :             }
    1133              : 
    1134          120 :             data_t my_data;
    1135          120 :             my_data.f_color = rand(),
    1136          120 :             my_data.f_height = rand(),
    1137          240 :             my_data.f_status = rand(),
    1138          120 :             my_data.f_width = rand(),
    1139              : 
    1140          120 :             values[index] = my_data;
    1141          120 :             order.push_back(index);
    1142              : 
    1143          360 :             out.add_value("set", index, my_data);
    1144          120 :         }
    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          120 :             static bool process_hunk(
    1161              :                           snapdev::deserializer<std::stringstream> & in
    1162              :                         , snapdev::field_t const & field
    1163              :                         , value_t & values)
    1164              :             {
    1165          120 :                 CATCH_REQUIRE(field.f_name == "set");
    1166          120 :                 CATCH_REQUIRE_FALSE(field.f_sub_name.empty());
    1167          120 :                 CATCH_REQUIRE(field.f_index == -1);
    1168          120 :                 CATCH_REQUIRE(values.find(field.f_sub_name) != values.end());
    1169              : 
    1170          120 :                 CATCH_REQUIRE(field.f_size == sizeof(data_t));
    1171              : 
    1172          120 :                 data_t value;
    1173          120 :                 in.read_data(value);
    1174          120 :                 data_t expected(values[field.f_sub_name]);
    1175          120 :                 CATCH_REQUIRE(value == expected);
    1176              : 
    1177          240 :                 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            4 :         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            5 :             void serialize(snapdev::serializer<std::stringstream> & out) const
    1207              :             {
    1208           15 :                 out.add_value("name", f_name);
    1209            5 :             }
    1210              : 
    1211            5 :             bool process_hunk(
    1212              :                   snapdev::deserializer<std::stringstream> & in
    1213              :                 , snapdev::field_t const & field)
    1214              :             {
    1215            5 :                 CATCH_REQUIRE(field.f_sub_name.empty());
    1216            5 :                 CATCH_REQUIRE(field.f_index == -1);
    1217              : 
    1218            5 :                 if(field.f_name == "name")
    1219              :                 {
    1220            5 :                     std::string value;
    1221            5 :                     in.read_data(value);
    1222            5 :                     CATCH_REQUIRE(f_name == value);
    1223            5 :                 }
    1224              :                 else
    1225              :                 {
    1226            0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
    1227              :                 }
    1228              : 
    1229            5 :                 return true;
    1230              :             }
    1231              : 
    1232            5 :             void set_name(std::string const & name)
    1233              :             {
    1234            5 :                 f_name = name;
    1235            5 :             }
    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           22 :                 for(std::size_t idx(0); idx < std::size(f_sizes); ++idx)
    1247              :                 {
    1248           30 :                     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           20 :                     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            6 :                 for(int idx(0); idx < max; ++idx)
    1287              :                 {
    1288            5 :                     std::string name;
    1289            5 :                     int len(rand() % 25 + 10);
    1290          154 :                     for(int j(0); j < len; ++j)
    1291              :                     {
    1292          149 :                         name += 'a' + rand() % 26;
    1293              :                     }
    1294            5 :                     t1 t;
    1295            5 :                     t.set_name(name);
    1296            5 :                     f_t1.push_back(t);
    1297            5 :                 }
    1298              : 
    1299            1 :                 int const array_max(rand() % 90 + 10);
    1300           94 :                 for(int idx(0); idx < array_max; ++idx)
    1301              :                 {
    1302           93 :                     float nominator(static_cast<float>(rand()));
    1303           93 :                     float denominator(0.0f);
    1304              : #pragma GCC diagnostic push
    1305              : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1306          186 :                     while(denominator == 0.0f)
    1307              :                     {
    1308           93 :                         denominator = static_cast<float>(rand());
    1309              :                     }
    1310              : #pragma GCC diagnostic pop
    1311           93 :                     f_t3.push_back(nominator / denominator);
    1312              :                 }
    1313            1 :             }
    1314              : 
    1315            1 :             void serialize(snapdev::serializer<std::stringstream> & out) const
    1316              :             {
    1317            3 :                 out.add_value("count", f_count);
    1318            3 :                 out.add_value("age", f_age);
    1319              : 
    1320              :                 {
    1321            1 :                     int const max(static_cast<int>(f_t1.size()));
    1322            6 :                     for(int idx(0); idx < max; ++idx)
    1323              :                     {
    1324           15 :                         snapdev::recursive r(out, "t1_array");
    1325            5 :                         f_t1[idx].serialize(out);
    1326            5 :                     }
    1327              :                 }
    1328              : 
    1329            3 :                 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            5 :                 out.add_value("flower-color", std::string("bluish"));
    1337            3 :                 out.add_value("flower-height", std::string());  // unknown
    1338            3 :                 out.add_value_if_not_empty("flower-name", std::string());  // unknown -- not added
    1339              : 
    1340            3 :                 out.add_value("dog-color", "red");
    1341            3 :                 out.add_value("dog-height", "");  // unknown
    1342            5 :                 out.add_value_if_not_empty("dog-name", "");  // unknown -- not added
    1343            3 :                 out.add_value("dog-nothing", nullptr);  // unknown -- not added
    1344            5 :                 out.add_value_if_not_empty("dog-eye-color", "green");
    1345            1 :             }
    1346              : 
    1347           14 :             bool process_hunk(
    1348              :                   snapdev::deserializer<std::stringstream> & in
    1349              :                 , snapdev::field_t const & field)
    1350              :             {
    1351           14 :                 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           13 :                 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           12 :                 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            5 :                     CATCH_REQUIRE(field.f_index == -1);
    1368            5 :                     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            5 :                     CATCH_REQUIRE(f_t1_index < f_t1.size());
    1376              : 
    1377           15 :                     snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1378           10 :                                   &t1::process_hunk
    1379           10 :                                 , &f_t1[f_t1_index]
    1380              :                                 , std::placeholders::_1
    1381           10 :                                 , std::placeholders::_2));
    1382            5 :                     bool const r(in.deserialize(func));
    1383            5 :                     CATCH_REQUIRE(r);
    1384              : 
    1385            5 :                     ++f_t1_index;
    1386            5 :                 }
    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            3 :                     CATCH_REQUIRE(value.length() == std::string("bluish").length());
    1412            3 :                     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            3 :                     CATCH_REQUIRE(value.length() == std::string("red").length());
    1433            3 :                     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            3 :                     CATCH_REQUIRE(value == std::string("green"));
    1455            1 :                 }
    1456              :                 else
    1457              :                 {
    1458            0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
    1459              :                 }
    1460              : 
    1461           14 :                 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            5 :         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            5 :         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            7 :         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            9 :         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            5 :         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          238 :         for(std::size_t idx(0); idx < max; ++idx)
    1581              :         {
    1582          237 :             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          401 :         for(std::size_t idx(0); idx < sub_max; ++idx)
    1615              :         {
    1616          400 :             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          320 :             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          320 :             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          360 :             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            4 :         CATCH_REQUIRE_THROWS_MATCHES(
    1676              :                   snapdev::deserializer<std::stringstream>(buffer)
    1677              :                 , snapdev::brs_magic_missing
    1678              :                 , Catch::Matchers::ExceptionMessage(
    1679              :                           "brs_error: magic missing at 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            4 :         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            3 :         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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :                 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            3 :         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
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions