LCOV - code coverage report
Current view: top level - tests - catch_brs.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 970 1005 96.5 %
Date: 2022-07-09 19:51:09 Functions: 37 45 82.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2022  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           3 : CATCH_TEST_CASE("bitfield_size", "[bitfield]")
      44             : {
      45           2 :     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             :     CATCH_END_SECTION()
      57           1 : }
      58             : 
      59             : 
      60          15 : CATCH_TEST_CASE("basic_types", "[basic]")
      61             : {
      62          26 :     CATCH_START_SECTION("brs: push/restore char")
      63             :     {
      64           2 :         std::stringstream buffer;
      65           1 :         snapdev::serializer out(buffer);
      66             : 
      67           2 :         std::string data(buffer.str());
      68           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
      69             : 
      70           1 :         CATCH_REQUIRE(data[0] == 'B');
      71           1 :         CATCH_REQUIRE(data[1] == 'R');
      72           1 :         CATCH_REQUIRE(data[2] == 'L');
      73           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
      74             : 
      75           1 :         char value = 33;
      76           1 :         out.add_value("orange", value);
      77             : 
      78           1 :         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           2 :         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           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
     133           2 :                       &processor::process_hunk
     134             :                     , std::placeholders::_1
     135           3 :                     , std::placeholders::_2));
     136           1 :         bool const r(in.deserialize(func));
     137           1 :         CATCH_REQUIRE(r);
     138             :     }
     139             :     CATCH_END_SECTION()
     140             : 
     141          26 :     CATCH_START_SECTION("brs: push/restore signed char")
     142             :     {
     143           2 :         std::stringstream buffer;
     144           1 :         snapdev::serializer out(buffer);
     145             : 
     146           2 :         std::string data(buffer.str());
     147           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     148             : 
     149           1 :         CATCH_REQUIRE(data[0] == 'B');
     150           1 :         CATCH_REQUIRE(data[1] == 'R');
     151           1 :         CATCH_REQUIRE(data[2] == 'L');
     152           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     153             : 
     154           1 :         signed char value = -43;
     155           1 :         out.add_value("orange", value);
     156             : 
     157             :         // make sure it did not get smashed
     158           1 :         data = buffer.str();
     159           1 :         CATCH_REQUIRE(data[0] == 'B');
     160           1 :         CATCH_REQUIRE(data[1] == 'R');
     161           1 :         CATCH_REQUIRE(data[2] == 'L');
     162           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     163             : 
     164           1 :         CATCH_REQUIRE(data[4] == 6 << 2);  // hunk_sizes_t
     165           1 :         CATCH_REQUIRE(data[5] == 1 << 1);
     166           1 :         CATCH_REQUIRE(data[6] == 0);
     167           1 :         CATCH_REQUIRE(data[7] == 0);
     168             : 
     169           1 :         CATCH_REQUIRE(data[8] == 'o');    // name
     170           1 :         CATCH_REQUIRE(data[9] == 'r');
     171           1 :         CATCH_REQUIRE(data[10] == 'a');
     172           1 :         CATCH_REQUIRE(data[11] == 'n');
     173           1 :         CATCH_REQUIRE(data[12] == 'g');
     174           1 :         CATCH_REQUIRE(data[13] == 'e');
     175             : 
     176           1 :         CATCH_REQUIRE(static_cast<signed char>(data[14]) == -43);   // value
     177             : 
     178             :         struct processor
     179             :         {
     180           1 :             static bool process_hunk(
     181             :                           snapdev::deserializer<std::stringstream> & in
     182             :                         , snapdev::field_t const & field)
     183             :             {
     184           1 :                 CATCH_REQUIRE(field.f_name == "orange");
     185           1 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     186           1 :                 CATCH_REQUIRE(field.f_index == -1);
     187           1 :                 CATCH_REQUIRE(field.f_size == 1);
     188           1 :                 signed char c;
     189           1 :                 in.read_data(c);
     190           1 :                 CATCH_REQUIRE(c == -43);
     191           1 :                 return true;
     192             :             }
     193             :         };
     194             : 
     195             :         // Note: you don't usually end up re-using the serializer buffer
     196             :         //       but here it's practical
     197             :         //
     198           1 :         buffer.clear();
     199             : 
     200           2 :         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           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
     206           2 :                       &processor::process_hunk
     207             :                     , std::placeholders::_1
     208           3 :                     , std::placeholders::_2));
     209           1 :         bool const r(in.deserialize(func));
     210           1 :         CATCH_REQUIRE(r);
     211             :     }
     212             :     CATCH_END_SECTION()
     213             : 
     214          26 :     CATCH_START_SECTION("brs: push/restore unsigned char")
     215             :     {
     216           2 :         std::stringstream buffer;
     217           1 :         snapdev::serializer out(buffer);
     218             : 
     219           2 :         std::string data(buffer.str());
     220           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     221             : 
     222           1 :         CATCH_REQUIRE(data[0] == 'B');
     223           1 :         CATCH_REQUIRE(data[1] == 'R');
     224           1 :         CATCH_REQUIRE(data[2] == 'L');
     225           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     226             : 
     227           1 :         unsigned char value = 200;
     228           1 :         out.add_value("orange", value);
     229             : 
     230             :         // make sure it did not get smashed
     231           1 :         data = buffer.str();
     232           1 :         CATCH_REQUIRE(data[0] == 'B');
     233           1 :         CATCH_REQUIRE(data[1] == 'R');
     234           1 :         CATCH_REQUIRE(data[2] == 'L');
     235           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     236             : 
     237           1 :         CATCH_REQUIRE(data[4] == 6 << 2);  // hunk_sizes_t
     238           1 :         CATCH_REQUIRE(data[5] == 1 << 1);
     239           1 :         CATCH_REQUIRE(data[6] == 0);
     240           1 :         CATCH_REQUIRE(data[7] == 0);
     241             : 
     242           1 :         CATCH_REQUIRE(data[8] == 'o');    // name
     243           1 :         CATCH_REQUIRE(data[9] == 'r');
     244           1 :         CATCH_REQUIRE(data[10] == 'a');
     245           1 :         CATCH_REQUIRE(data[11] == 'n');
     246           1 :         CATCH_REQUIRE(data[12] == 'g');
     247           1 :         CATCH_REQUIRE(data[13] == 'e');
     248             : 
     249           1 :         CATCH_REQUIRE(static_cast<unsigned char>(data[14]) == 200);   // value
     250             : 
     251             :         struct processor
     252             :         {
     253           1 :             static bool process_hunk(
     254             :                           snapdev::deserializer<std::stringstream> & in
     255             :                         , snapdev::field_t const & field)
     256             :             {
     257           1 :                 CATCH_REQUIRE(field.f_name == "orange");
     258           1 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     259           1 :                 CATCH_REQUIRE(field.f_index == -1);
     260           1 :                 CATCH_REQUIRE(field.f_size == 1);
     261           1 :                 unsigned char c;
     262           1 :                 in.read_data(c);
     263           1 :                 CATCH_REQUIRE(c == 200);
     264           1 :                 return true;
     265             :             }
     266             :         };
     267             : 
     268             :         // Note: you don't usually end up re-using the serializer buffer
     269             :         //       but here it's practical
     270             :         //
     271           1 :         buffer.clear();
     272             : 
     273           2 :         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           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
     279           2 :                       &processor::process_hunk
     280             :                     , std::placeholders::_1
     281           3 :                     , std::placeholders::_2));
     282           1 :         bool const r(in.deserialize(func));
     283           1 :         CATCH_REQUIRE(r);
     284             :     }
     285             :     CATCH_END_SECTION()
     286             : 
     287          26 :     CATCH_START_SECTION("brs: push/restore shorts (16 bits)")
     288             :     {
     289           2 :         std::stringstream buffer;
     290           1 :         snapdev::serializer out(buffer);
     291             : 
     292           2 :         std::string data(buffer.str());
     293           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     294             : 
     295           1 :         CATCH_REQUIRE(data[0] == 'B');
     296           1 :         CATCH_REQUIRE(data[1] == 'R');
     297           1 :         CATCH_REQUIRE(data[2] == 'L');
     298           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     299             : 
     300           1 :         std::int16_t const purple = 3003;
     301           1 :         out.add_value("purple", purple);
     302             : 
     303           1 :         std::uint16_t const black = 65001;
     304           1 :         out.add_value("black", black);
     305             : 
     306             :         // make sure it did not get smashed
     307           1 :         data = buffer.str();
     308           1 :         CATCH_REQUIRE(data[0] == 'B');
     309           1 :         CATCH_REQUIRE(data[1] == 'R');
     310           1 :         CATCH_REQUIRE(data[2] == 'L');
     311           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     312             : 
     313           1 :         CATCH_REQUIRE(data[4] == 6 << 2);  // hunk_sizes_t
     314           1 :         CATCH_REQUIRE(data[5] == 2 << 1);
     315           1 :         CATCH_REQUIRE(data[6] == 0);
     316           1 :         CATCH_REQUIRE(data[7] == 0);
     317             : 
     318           1 :         CATCH_REQUIRE(data[8] == 'p');    // name
     319           1 :         CATCH_REQUIRE(data[9] == 'u');
     320           1 :         CATCH_REQUIRE(data[10] == 'r');
     321           1 :         CATCH_REQUIRE(data[11] == 'p');
     322           1 :         CATCH_REQUIRE(data[12] == 'l');
     323           1 :         CATCH_REQUIRE(data[13] == 'e');
     324             : 
     325             : #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
     326             :         CATCH_REQUIRE(static_cast<std::uint8_t>(data[14]) * 256 + static_cast<std::uint8_t>(data[15]) == 3003);   // value
     327             : #else
     328           1 :         CATCH_REQUIRE(static_cast<std::uint8_t>(data[14]) + static_cast<std::uint8_t>(data[15]) * 256 == 3003);   // value
     329             : #endif
     330             : 
     331             :         struct processor
     332             :         {
     333           2 :             static bool process_hunk(
     334             :                           snapdev::deserializer<std::stringstream> & in
     335             :                         , snapdev::field_t const & field
     336             :                         , std::int16_t purple
     337             :                         , std::uint16_t black)
     338             :             {
     339           2 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     340           2 :                 CATCH_REQUIRE(field.f_index == -1);
     341           2 :                 CATCH_REQUIRE(field.f_size == 2);
     342           2 :                 if(field.f_name == "purple")
     343             :                 {
     344           1 :                     std::int16_t value;
     345           1 :                     in.read_data(value);
     346           1 :                     CATCH_REQUIRE(value == purple);
     347             :                 }
     348           1 :                 else if(field.f_name == "black")
     349             :                 {
     350           1 :                     std::uint16_t value;
     351           1 :                     in.read_data(value);
     352           1 :                     CATCH_REQUIRE(value == black);
     353             :                 }
     354             :                 else
     355             :                 {
     356           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
     357             :                 }
     358           2 :                 return true;
     359             :             }
     360             :         };
     361             : 
     362             :         // Note: you don't usually end up re-using the serializer buffer
     363             :         //       but here it's practical
     364             :         //
     365           1 :         buffer.clear();
     366             : 
     367           2 :         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           4 :         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           3 :                     , black));
     378           1 :         bool const r(in.deserialize(func));
     379           1 :         CATCH_REQUIRE(r);
     380             :     }
     381             :     CATCH_END_SECTION()
     382             : 
     383          26 :     CATCH_START_SECTION("brs: push/restore ints (32 bits)")
     384             :     {
     385           2 :         std::stringstream buffer;
     386           1 :         snapdev::serializer out(buffer);
     387             : 
     388           2 :         std::string data(buffer.str());
     389           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     390             : 
     391           1 :         CATCH_REQUIRE(data[0] == 'B');
     392           1 :         CATCH_REQUIRE(data[1] == 'R');
     393           1 :         CATCH_REQUIRE(data[2] == 'L');
     394           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     395             : 
     396           1 :         std::int32_t const red = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     397           1 :         out.add_value("red", red);
     398             : 
     399           1 :         std::uint32_t const blue = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     400           1 :         out.add_value("blue", blue);
     401             : 
     402             :         // make sure it did not get smashed
     403           1 :         data = buffer.str();
     404           1 :         CATCH_REQUIRE(data[0] == 'B');
     405           1 :         CATCH_REQUIRE(data[1] == 'R');
     406           1 :         CATCH_REQUIRE(data[2] == 'L');
     407           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     408             : 
     409           1 :         CATCH_REQUIRE(data[4] == 3 << 2);  // hunk_sizes_t
     410           1 :         CATCH_REQUIRE(data[5] == 4 << 1);
     411           1 :         CATCH_REQUIRE(data[6] == 0);
     412           1 :         CATCH_REQUIRE(data[7] == 0);
     413             : 
     414           1 :         CATCH_REQUIRE(data[8] == 'r');    // name
     415           1 :         CATCH_REQUIRE(data[9] == 'e');
     416           1 :         CATCH_REQUIRE(data[10] == 'd');
     417             : 
     418             : #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
     419             :         CATCH_REQUIRE(
     420             :                   static_cast<std::uint8_t>(data[11]) * 0x1000000
     421             :                 + static_cast<std::uint8_t>(data[12]) * 0x10000
     422             :                 + static_cast<std::uint8_t>(data[13]) * 0x100
     423             :                 + static_cast<std::uint8_t>(data[14]) * 0x1 == red);   // value
     424             : #else
     425           1 :         CATCH_REQUIRE(
     426             :                   static_cast<std::uint8_t>(data[14]) * 0x1000000
     427             :                 + static_cast<std::uint8_t>(data[13]) * 0x10000
     428             :                 + static_cast<std::uint8_t>(data[12]) * 0x100
     429             :                 + static_cast<std::uint8_t>(data[11]) * 0x1 == red);   // value
     430             : #endif
     431             : 
     432             :         struct processor
     433             :         {
     434           2 :             static bool process_hunk(
     435             :                           snapdev::deserializer<std::stringstream> & in
     436             :                         , snapdev::field_t const & field
     437             :                         , std::int32_t red
     438             :                         , std::uint32_t blue)
     439             :             {
     440           2 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     441           2 :                 CATCH_REQUIRE(field.f_index == -1);
     442           2 :                 CATCH_REQUIRE(field.f_size == 4);
     443           2 :                 if(field.f_name == "red")
     444             :                 {
     445           1 :                     std::int32_t value;
     446           1 :                     in.read_data(value);
     447           1 :                     CATCH_REQUIRE(value == red);
     448             :                 }
     449           1 :                 else if(field.f_name == "blue")
     450             :                 {
     451           1 :                     std::uint32_t value;
     452           1 :                     in.read_data(value);
     453           1 :                     CATCH_REQUIRE(value == blue);
     454             :                 }
     455             :                 else
     456             :                 {
     457           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
     458             :                 }
     459           2 :                 return true;
     460             :             }
     461             :         };
     462             : 
     463             :         // Note: you don't usually end up re-using the serializer buffer
     464             :         //       but here it's practical
     465             :         //
     466           1 :         buffer.clear();
     467             : 
     468           2 :         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           4 :         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           3 :                     , blue));
     479           1 :         bool const r(in.deserialize(func));
     480           1 :         CATCH_REQUIRE(r);
     481             :     }
     482             :     CATCH_END_SECTION()
     483             : 
     484          26 :     CATCH_START_SECTION("brs: push/restore ints (64 bits)")
     485             :     {
     486           2 :         std::stringstream buffer;
     487           1 :         snapdev::serializer out(buffer);
     488             : 
     489           2 :         std::string data(buffer.str());
     490           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     491             : 
     492           1 :         CATCH_REQUIRE(data[0] == 'B');
     493           1 :         CATCH_REQUIRE(data[1] == 'R');
     494           1 :         CATCH_REQUIRE(data[2] == 'L');
     495           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     496             : 
     497           1 :         std::int64_t const white = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     498           1 :         out.add_value("white", white);
     499             : 
     500           1 :         std::uint64_t const gray = static_cast<std::int32_t>(SNAP_CATCH2_NAMESPACE::rand_int64());
     501           1 :         out.add_value("gray", gray);
     502             : 
     503             :         // make sure it did not get smashed
     504           1 :         data = buffer.str();
     505           1 :         CATCH_REQUIRE(data[0] == 'B');
     506           1 :         CATCH_REQUIRE(data[1] == 'R');
     507           1 :         CATCH_REQUIRE(data[2] == 'L');
     508           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     509             : 
     510           1 :         CATCH_REQUIRE(data[4] == 5 << 2);  // hunk_sizes_t
     511           1 :         CATCH_REQUIRE(data[5] == 8 << 1);
     512           1 :         CATCH_REQUIRE(data[6] == 0);
     513           1 :         CATCH_REQUIRE(data[7] == 0);
     514             : 
     515           1 :         CATCH_REQUIRE(data[8] == 'w');    // name
     516           1 :         CATCH_REQUIRE(data[9] == 'h');
     517           1 :         CATCH_REQUIRE(data[10] == 'i');
     518           1 :         CATCH_REQUIRE(data[11] == 't');
     519           1 :         CATCH_REQUIRE(data[12] == 'e');
     520             : 
     521             :         struct processor
     522             :         {
     523           2 :             static bool process_hunk(
     524             :                           snapdev::deserializer<std::stringstream> & in
     525             :                         , snapdev::field_t const & field
     526             :                         , std::int64_t white
     527             :                         , std::uint64_t gray)
     528             :             {
     529           2 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     530           2 :                 CATCH_REQUIRE(field.f_index == -1);
     531           2 :                 CATCH_REQUIRE(field.f_size == 8);
     532           2 :                 if(field.f_name == "white")
     533             :                 {
     534           1 :                     std::int64_t value;
     535           1 :                     in.read_data(value);
     536           1 :                     CATCH_REQUIRE(value == white);
     537             :                 }
     538           1 :                 else if(field.f_name == "gray")
     539             :                 {
     540           1 :                     std::uint64_t value;
     541           1 :                     in.read_data(value);
     542           1 :                     CATCH_REQUIRE(value == gray);
     543             :                 }
     544             :                 else
     545             :                 {
     546           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
     547             :                 }
     548           2 :                 return true;
     549             :             }
     550             :         };
     551             : 
     552             :         // Note: you don't usually end up re-using the serializer buffer
     553             :         //       but here it's practical
     554             :         //
     555           1 :         buffer.clear();
     556             : 
     557           2 :         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           4 :         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           3 :                     , gray));
     568           1 :         bool const r(in.deserialize(func));
     569           1 :         CATCH_REQUIRE(r);
     570             :     }
     571             :     CATCH_END_SECTION()
     572             : 
     573          26 :     CATCH_START_SECTION("brs: push/restore floats")
     574             :     {
     575           2 :         std::stringstream buffer;
     576           1 :         snapdev::serializer out(buffer);
     577             : 
     578           2 :         std::string data(buffer.str());
     579           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     580             : 
     581           1 :         CATCH_REQUIRE(data[0] == 'B');
     582           1 :         CATCH_REQUIRE(data[1] == 'R');
     583           1 :         CATCH_REQUIRE(data[2] == 'L');
     584           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     585             : 
     586           1 :         float const green = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
     587           1 :                           / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
     588           1 :         out.add_value("green", green);
     589             : 
     590           1 :         double const yellow = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
     591           1 :                             / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
     592           1 :         out.add_value("yellow", yellow);
     593             : 
     594           1 :         long double const fushia = static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64())
     595           1 :                                  / static_cast<float>(SNAP_CATCH2_NAMESPACE::rand_int64());
     596           1 :         out.add_value("fushia", fushia);
     597             : 
     598             :         // make sure it did not get smashed
     599           1 :         data = buffer.str();
     600           1 :         CATCH_REQUIRE(data[0] == 'B');
     601           1 :         CATCH_REQUIRE(data[1] == 'R');
     602           1 :         CATCH_REQUIRE(data[2] == 'L');
     603           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     604             : 
     605           1 :         CATCH_REQUIRE(data[4] == 5 << 2);  // hunk_sizes_t
     606           1 :         CATCH_REQUIRE(data[5] == 4 << 1);
     607           1 :         CATCH_REQUIRE(data[6] == 0);
     608           1 :         CATCH_REQUIRE(data[7] == 0);
     609             : 
     610           1 :         CATCH_REQUIRE(data[8] == 'g');    // name
     611           1 :         CATCH_REQUIRE(data[9] == 'r');
     612           1 :         CATCH_REQUIRE(data[10] == 'e');
     613           1 :         CATCH_REQUIRE(data[11] == 'e');
     614           1 :         CATCH_REQUIRE(data[12] == 'n');
     615             : 
     616             :         struct processor
     617             :         {
     618           3 :             static bool process_hunk(
     619             :                           snapdev::deserializer<std::stringstream> & in
     620             :                         , snapdev::field_t const & field
     621             :                         , float green
     622             :                         , double yellow
     623             :                         , long double fushia)
     624             :             {
     625           3 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     626           3 :                 CATCH_REQUIRE(field.f_index == -1);
     627           3 :                 if(field.f_name == "green")
     628             :                 {
     629           1 :                     CATCH_REQUIRE(field.f_size == 4);
     630             : 
     631           1 :                     float value;
     632           1 :                     in.read_data(value);
     633           1 :                     CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, green, 0.0f));
     634             :                 }
     635           2 :                 else if(field.f_name == "yellow")
     636             :                 {
     637           1 :                     CATCH_REQUIRE(field.f_size == 8);
     638             : 
     639           1 :                     double value;
     640           1 :                     in.read_data(value);
     641           1 :                     CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, yellow, 0.0));
     642             :                 }
     643           1 :                 else if(field.f_name == "fushia")
     644             :                 {
     645           1 :                     CATCH_REQUIRE(field.f_size == 16);
     646             : 
     647           1 :                     long double value;
     648           1 :                     in.read_data(value);
     649           1 :                     CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(value, fushia, 0.0L));
     650             :                 }
     651             :                 else
     652             :                 {
     653           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
     654             :                 }
     655           3 :                 return true;
     656             :             }
     657             :         };
     658             : 
     659             :         // Note: you don't usually end up re-using the serializer buffer
     660             :         //       but here it's practical
     661             :         //
     662           1 :         buffer.clear();
     663             : 
     664           2 :         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           4 :         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           3 :                     , fushia));
     676           1 :         bool const r(in.deserialize(func));
     677           1 :         CATCH_REQUIRE(r);
     678             :     }
     679             :     CATCH_END_SECTION()
     680             : 
     681          26 :     CATCH_START_SECTION("brs: push/restore string")
     682             :     {
     683           2 :         std::stringstream buffer;
     684           1 :         snapdev::serializer out(buffer);
     685             : 
     686           2 :         std::string data(buffer.str());
     687           1 :         CATCH_REQUIRE(data.length() == sizeof(snapdev::magic_t));
     688             : 
     689           1 :         CATCH_REQUIRE(data[0] == 'B');
     690           1 :         CATCH_REQUIRE(data[1] == 'R');
     691           1 :         CATCH_REQUIRE(data[2] == 'L');
     692           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     693             : 
     694           2 :         std::string message("this is the message we are going to serialize");
     695           1 :         out.add_value("message",  message);
     696             : 
     697             :         // make sure it did not get smashed
     698           1 :         data = buffer.str();
     699           1 :         CATCH_REQUIRE(data[0] == 'B');
     700           1 :         CATCH_REQUIRE(data[1] == 'R');
     701           1 :         CATCH_REQUIRE(data[2] == 'L');
     702           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     703             : 
     704           1 :         CATCH_REQUIRE(data[4] == 7 << 2);  // hunk_sizes_t
     705           1 :         CATCH_REQUIRE(data[5] == 45 << 1);
     706           1 :         CATCH_REQUIRE(data[6] == 0);
     707           1 :         CATCH_REQUIRE(data[7] == 0);
     708             : 
     709           1 :         CATCH_REQUIRE(data[8] == 'm');    // name
     710           1 :         CATCH_REQUIRE(data[9] == 'e');
     711           1 :         CATCH_REQUIRE(data[10] == 's');
     712           1 :         CATCH_REQUIRE(data[11] == 's');
     713           1 :         CATCH_REQUIRE(data[12] == 'a');
     714           1 :         CATCH_REQUIRE(data[13] == 'g');
     715           1 :         CATCH_REQUIRE(data[14] == 'e');
     716             : 
     717             :         struct processor
     718             :         {
     719           1 :             static bool process_hunk(
     720             :                           snapdev::deserializer<std::stringstream> & in
     721             :                         , snapdev::field_t const & field
     722             :                         , std::string message)
     723             :             {
     724           1 :                 CATCH_REQUIRE(field.f_name == "message");
     725           1 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     726           1 :                 CATCH_REQUIRE(field.f_index == -1);
     727           1 :                 CATCH_REQUIRE(field.f_size == 45);
     728             : 
     729           2 :                 std::string value;
     730           1 :                 in.read_data(value);
     731           1 :                 CATCH_REQUIRE(value == message);
     732             : 
     733           2 :                 return true;
     734             :             }
     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           2 :         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           3 :                     , message));
     752           1 :         bool const r(in.deserialize(func));
     753           1 :         CATCH_REQUIRE(r);
     754             :     }
     755             :     CATCH_END_SECTION()
     756             : 
     757          26 :     CATCH_START_SECTION("brs: push/restore array (varying name)")
     758             :     {
     759           2 :         std::stringstream buffer;
     760           1 :         snapdev::serializer out(buffer);
     761             : 
     762           2 :         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           2 :         std::vector<int> order;
     771             :         typedef std::map<int, std::string> value_t;
     772           2 :         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          50 :             std::string str;
     785          25 :             int max(rand() % 25 + 1);
     786         327 :             for(int j(0); j < max; ++j)
     787             :             {
     788         302 :                 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             :         }
     795             : 
     796             :         // make sure it did not get smashed
     797           1 :         data = buffer.str();
     798           1 :         CATCH_REQUIRE(data[0] == 'B');
     799           1 :         CATCH_REQUIRE(data[1] == 'R');
     800           1 :         CATCH_REQUIRE(data[2] == 'L');
     801           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
     802             : 
     803             :         struct processor
     804             :         {
     805          25 :             static bool process_hunk(
     806             :                           snapdev::deserializer<std::stringstream> & in
     807             :                         , snapdev::field_t const & field
     808             :                         , value_t & values)
     809             :             {
     810          25 :                 CATCH_REQUIRE(field.f_sub_name.empty());
     811          25 :                 CATCH_REQUIRE(field.f_index != -1);
     812             : 
     813          50 :                 std::string expected_name("str" + std::to_string(field.f_index));
     814          25 :                 CATCH_REQUIRE(field.f_name == expected_name);
     815             : 
     816          25 :                 CATCH_REQUIRE(field.f_size == values[field.f_index].length());
     817             : 
     818          50 :                 std::string value;
     819          25 :                 in.read_data(value);
     820          25 :                 CATCH_REQUIRE(value == values[field.f_index]);
     821             : 
     822          50 :                 return true;
     823             :             }
     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           2 :         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           3 :                     , values));
     841           1 :         bool const r(in.deserialize(func));
     842           1 :         CATCH_REQUIRE(r);
     843             :     }
     844             :     CATCH_END_SECTION()
     845             : 
     846          26 :     CATCH_START_SECTION("brs: push/restore array (same name)")
     847             :     {
     848           2 :         std::stringstream buffer;
     849           1 :         snapdev::serializer out(buffer);
     850             : 
     851           2 :         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           2 :         std::vector<int> order;
     863             :         typedef std::map<int, std::string> value_t;
     864           2 :         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          27 :                 index = rand() % 256;
     872          26 :                 if(values.find(index) == values.end())
     873             :                 {
     874          25 :                     break;
     875             :                 }
     876             :             }
     877          50 :             std::string str;
     878          25 :             int max(rand() % 25 + 1);
     879         329 :             for(int j(0); j < max; ++j)
     880             :             {
     881         304 :                 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          12 :                 out.add_value("unique", index, str.c_str());
     890             :             }
     891             :             else
     892             :             {
     893             :                 // pass as an std::string
     894          13 :                 out.add_value("unique", index, str);
     895             :             }
     896             : 
     897             :             // nullptr does nothing
     898          25 :             out.add_value("unique", index + size, nullptr);
     899             :         }
     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          50 :                 std::string value;
     922          25 :                 in.read_data(value);
     923          25 :                 CATCH_REQUIRE(value == values[field.f_index]);
     924             : 
     925          50 :                 return true;
     926             :             }
     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           2 :         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           3 :                     , values));
     944           1 :         bool const r(in.deserialize(func));
     945           1 :         CATCH_REQUIRE(r);
     946             :     }
     947             :     CATCH_END_SECTION()
     948             : 
     949          26 :     CATCH_START_SECTION("brs: push/restore map of strings")
     950             :     {
     951           2 :         std::stringstream buffer;
     952           1 :         snapdev::serializer out(buffer);
     953             : 
     954           2 :         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           2 :         std::vector<std::string> order;
     966             :         typedef std::map<std::string, std::string> value_t;
     967           2 :         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          50 :             std::string index;
     973             :             for(;;)
     974             :             {
     975          25 :                 max = rand() % 25 + 1;
     976         366 :                 for(int j(0); j < max; ++j)
     977             :                 {
     978         341 :                     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          50 :             std::string str;
     988          25 :             if(i != empty)
     989             :             {
     990          24 :                 max = rand() % 25;
     991         318 :                 for(int j(0); j < max; ++j)
     992             :                 {
     993         294 :                     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          26 :                 if(str.empty()
    1003          13 :                 || (rand() & 1) != 0)
    1004             :                 {
    1005           6 :                     out.add_value("mapping", index, str);
    1006             :                 }
    1007             :                 else
    1008             :                 {
    1009           7 :                     out.add_value_if_not_empty("mapping", index, str);
    1010             :                 }
    1011             :             }
    1012             :             else
    1013             :             {
    1014             :                 // bare string
    1015             :                 //
    1016          12 :                 out.add_value("mapping", index, str.c_str());
    1017             :             }
    1018             : 
    1019          25 :             out.add_value("mapping", index + "a", nullptr);
    1020             :         }
    1021           1 :         out.add_value_if_not_empty("mapping", "last-index", std::string());
    1022             : 
    1023             : //{
    1024             : //std::ofstream p("t1.txt");
    1025             : //std::string s(buffer.str());
    1026             : //p << s;
    1027             : //}
    1028             : 
    1029             :         // make sure it did not get smashed
    1030           1 :         data = buffer.str();
    1031           1 :         CATCH_REQUIRE(data[0] == 'B');
    1032           1 :         CATCH_REQUIRE(data[1] == 'R');
    1033           1 :         CATCH_REQUIRE(data[2] == 'L');
    1034           1 :         CATCH_REQUIRE(data[3] == snapdev::BRS_VERSION);
    1035             : 
    1036             :         struct processor
    1037             :         {
    1038          25 :             static bool process_hunk(
    1039             :                           snapdev::deserializer<std::stringstream> & in
    1040             :                         , snapdev::field_t const & field
    1041             :                         , value_t & values)
    1042             :             {
    1043          25 :                 CATCH_REQUIRE(field.f_name == "mapping");
    1044          25 :                 CATCH_REQUIRE_FALSE(field.f_sub_name.empty());
    1045          25 :                 CATCH_REQUIRE(field.f_index == -1);
    1046          25 :                 CATCH_REQUIRE(values.find(field.f_sub_name) != values.end());
    1047             : 
    1048          25 :                 CATCH_REQUIRE(field.f_size == values[field.f_sub_name].length());
    1049             : 
    1050          50 :                 std::string value;
    1051          25 :                 in.read_data(value);
    1052          25 :                 CATCH_REQUIRE(value == values[field.f_sub_name]);
    1053             : 
    1054          50 :                 return true;
    1055             :             }
    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           2 :         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           3 :                     , values));
    1073           1 :         bool const r(in.deserialize(func));
    1074           1 :         CATCH_REQUIRE(r);
    1075             :     }
    1076             :     CATCH_END_SECTION()
    1077             : 
    1078          26 :     CATCH_START_SECTION("brs: push/restore map of struct")
    1079             :     {
    1080          49 :         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          49 :             bool operator == (data_t const & rhs) const
    1088             :             {
    1089             : #pragma GCC diagnostic push
    1090             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1091          49 :                 return f_color == rhs.f_color
    1092          49 :                     && f_height == rhs.f_height
    1093          49 :                     && f_status == rhs.f_status
    1094          98 :                     && f_width == rhs.f_width;
    1095             : #pragma GCC diagnostic pop
    1096             :             }
    1097             :         };
    1098             : 
    1099           2 :         std::stringstream buffer;
    1100           1 :         snapdev::serializer out(buffer);
    1101             : 
    1102           2 :         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           2 :         std::vector<std::string> order;
    1114             :         typedef std::map<std::string, data_t> value_t;
    1115           2 :         value_t values;
    1116           1 :         std::size_t const count(rand() % 100 + 25);
    1117          50 :         for(std::size_t i(0); i < count; ++i)
    1118             :         {
    1119          98 :             std::string index;
    1120             :             for(;;)
    1121             :             {
    1122          49 :                 int const max(rand() % 25 + 1);
    1123         681 :                 for(int j(0); j < max; ++j)
    1124             :                 {
    1125         632 :                     index += ' ' + rand() % ('~' + 1 - ' '); // ASCII except controls
    1126             :                 }
    1127          49 :                 if(values.find(index) == values.end())
    1128             :                 {
    1129             :                     // index is unique, use it
    1130          49 :                     break;
    1131             :                 }
    1132           0 :             }
    1133             : 
    1134          49 :             data_t my_data;
    1135          49 :             my_data.f_color = rand(),
    1136          98 :             my_data.f_height = rand(),
    1137          98 :             my_data.f_status = rand(),
    1138         147 :             my_data.f_width = rand(),
    1139             : 
    1140          49 :             values[index] = my_data;
    1141          49 :             order.push_back(index);
    1142             : 
    1143          49 :             out.add_value("set", index, my_data);
    1144             :         }
    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          49 :             static bool process_hunk(
    1161             :                           snapdev::deserializer<std::stringstream> & in
    1162             :                         , snapdev::field_t const & field
    1163             :                         , value_t & values)
    1164             :             {
    1165          49 :                 CATCH_REQUIRE(field.f_name == "set");
    1166          49 :                 CATCH_REQUIRE_FALSE(field.f_sub_name.empty());
    1167          49 :                 CATCH_REQUIRE(field.f_index == -1);
    1168          49 :                 CATCH_REQUIRE(values.find(field.f_sub_name) != values.end());
    1169             : 
    1170          49 :                 CATCH_REQUIRE(field.f_size == sizeof(data_t));
    1171             : 
    1172          49 :                 data_t value;
    1173          49 :                 in.read_data(value);
    1174          49 :                 data_t expected(values[field.f_sub_name]);
    1175          49 :                 CATCH_REQUIRE(value == expected);
    1176             : 
    1177          49 :                 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           2 :         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           3 :                     , values));
    1196           1 :         bool const r(in.deserialize(func));
    1197           1 :         CATCH_REQUIRE(r);
    1198             :     }
    1199             :     CATCH_END_SECTION()
    1200             : 
    1201          26 :     CATCH_START_SECTION("brs: push/restore recursive")
    1202             :     {
    1203          38 :         class t1
    1204             :         {
    1205             :         public:
    1206           6 :             void serialize(snapdev::serializer<std::stringstream> & out) const
    1207             :             {
    1208           6 :                 out.add_value("name", f_name);
    1209           6 :             }
    1210             : 
    1211           6 :             bool process_hunk(
    1212             :                   snapdev::deserializer<std::stringstream> & in
    1213             :                 , snapdev::field_t const & field)
    1214             :             {
    1215           6 :                 CATCH_REQUIRE(field.f_sub_name.empty());
    1216           6 :                 CATCH_REQUIRE(field.f_index == -1);
    1217             : 
    1218           6 :                 if(field.f_name == "name")
    1219             :                 {
    1220          12 :                     std::string value;
    1221           6 :                     in.read_data(value);
    1222           6 :                     CATCH_REQUIRE(f_name == value);
    1223             :                 }
    1224             :                 else
    1225             :                 {
    1226           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
    1227             :                 }
    1228             : 
    1229           6 :                 return true;
    1230             :             }
    1231             : 
    1232           6 :             void set_name(std::string const & name)
    1233             :             {
    1234           6 :                 f_name = name;
    1235           6 :             }
    1236             : 
    1237             :         private:
    1238             :             std::string     f_name = "--undefined--";
    1239             :         };
    1240             : 
    1241          11 :         class t2
    1242             :         {
    1243             :         public:
    1244           1 :             void serialize(snapdev::serializer<std::stringstream> & out) const
    1245             :             {
    1246          11 :                 for(std::size_t idx(0); idx < std::size(f_sizes); ++idx)
    1247             :                 {
    1248          10 :                     out.add_value("size", idx, f_sizes[idx]);
    1249             :                 }
    1250           1 :             }
    1251             : 
    1252          10 :             bool process_hunk(
    1253             :                   snapdev::deserializer<std::stringstream> & in
    1254             :                 , snapdev::field_t const & field)
    1255             :             {
    1256          10 :                 if(field.f_name == "size")
    1257             :                 {
    1258          10 :                     CATCH_REQUIRE(static_cast<std::size_t>(field.f_index) < std::size(f_sizes));
    1259             : 
    1260          10 :                     std::int32_t value;
    1261          10 :                     in.read_data(value);
    1262          10 :                     CATCH_REQUIRE(value == f_sizes[field.f_index]);
    1263             :                 }
    1264             :                 else
    1265             :                 {
    1266           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
    1267             :                 }
    1268             : 
    1269          10 :                 return true;
    1270             :             }
    1271             : 
    1272             :         private:
    1273             :             std::int32_t    f_sizes[10] = {
    1274           5 :                     rand(), rand(), rand(), rand(), rand(),
    1275           5 :                     rand(), rand(), rand(), rand(), rand(),
    1276             :                 };
    1277             :         };
    1278             : 
    1279             :         // c includes an array of t1's and one t2
    1280           1 :         class c
    1281             :         {
    1282             :         public:
    1283           1 :             c()
    1284           3 :             {
    1285           1 :                 int const max(rand() % 5 + 3);
    1286           7 :                 for(int idx(0); idx < max; ++idx)
    1287             :                 {
    1288          12 :                     std::string name;
    1289           6 :                     int len(rand() % 25 + 10);
    1290         186 :                     for(int j(0); j < len; ++j)
    1291             :                     {
    1292         180 :                         name += 'a' + rand() % 26;
    1293             :                     }
    1294          12 :                     t1 t;
    1295           6 :                     t.set_name(name);
    1296           6 :                     f_t1.push_back(t);
    1297             :                 }
    1298             : 
    1299           1 :                 int const array_max(rand() % 90 + 10);
    1300          64 :                 for(int idx(0); idx < array_max; ++idx)
    1301             :                 {
    1302          63 :                     float nominator(static_cast<float>(rand()));
    1303          63 :                     float denominator(0.0f);
    1304             : #pragma GCC diagnostic push
    1305             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1306         189 :                     while(denominator == 0.0f)
    1307             :                     {
    1308          63 :                         denominator = static_cast<float>(rand());
    1309             :                     }
    1310             : #pragma GCC diagnostic pop
    1311          63 :                     f_t3.push_back(nominator / denominator);
    1312             :                 }
    1313           1 :             }
    1314             : 
    1315           1 :             void serialize(snapdev::serializer<std::stringstream> & out) const
    1316             :             {
    1317           1 :                 out.add_value("count", f_count);
    1318           1 :                 out.add_value("age", f_age);
    1319             : 
    1320             :                 {
    1321           1 :                     int const max(static_cast<int>(f_t1.size()));
    1322           7 :                     for(int idx(0); idx < max; ++idx)
    1323             :                     {
    1324          12 :                         snapdev::recursive r(out, "t1_array");
    1325           6 :                         f_t1[idx].serialize(out);
    1326             :                     }
    1327             :                 }
    1328             : 
    1329           1 :                 out.add_value("float-array", f_t3);
    1330             : 
    1331             :                 {
    1332           2 :                     snapdev::recursive r(out, "t2");
    1333           1 :                     f_t2.serialize(out);
    1334             :                 }
    1335             : 
    1336           1 :                 out.add_value("flower-color", std::string("bluish"));
    1337           1 :                 out.add_value("flower-height", std::string());  // unknown
    1338           1 :                 out.add_value_if_not_empty("flower-name", std::string());  // unknown -- not added
    1339             : 
    1340           1 :                 out.add_value("dog-color", "red");
    1341           1 :                 out.add_value("dog-height", "");  // unknown
    1342           1 :                 out.add_value_if_not_empty("dog-name", "");  // unknown -- not added
    1343           1 :                 out.add_value("dog-nothing", nullptr);  // unknown -- not added
    1344           1 :                 out.add_value_if_not_empty("dog-eye-color", "green");
    1345           1 :             }
    1346             : 
    1347          15 :             bool process_hunk(
    1348             :                   snapdev::deserializer<std::stringstream> & in
    1349             :                 , snapdev::field_t const & field)
    1350             :             {
    1351          15 :                 if(field.f_name == "count")
    1352             :                 {
    1353           1 :                     int value;
    1354           1 :                     in.read_data(value);
    1355           1 :                     CATCH_REQUIRE(f_count == value);
    1356             :                 }
    1357          14 :                 else if(field.f_name == "age")
    1358             :                 {
    1359           1 :                     int value;
    1360           1 :                     in.read_data(value);
    1361           1 :                     CATCH_REQUIRE(f_age == value);
    1362             :                 }
    1363          13 :                 else if(field.f_name == "t1_array")
    1364             :                 {
    1365             :                     // this is a set of sub-classes so we do not have an index
    1366             :                     //
    1367           6 :                     CATCH_REQUIRE(field.f_index == -1);
    1368           6 :                     CATCH_REQUIRE(field.f_sub_name == std::string());
    1369             : 
    1370             :                     // in a normal implementation, here we would create a new
    1371             :                     // item and append it if the load succeeds; the test will
    1372             :                     // instead verify that the f_t1_index is still valid and
    1373             :                     // test load that next f_t1 object
    1374             :                     //
    1375           6 :                     CATCH_REQUIRE(f_t1_index < f_t1.size());
    1376             : 
    1377          24 :                     snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1378             :                                   &t1::process_hunk
    1379          12 :                                 , &f_t1[f_t1_index]
    1380             :                                 , std::placeholders::_1
    1381          18 :                                 , std::placeholders::_2));
    1382           6 :                     bool const r(in.deserialize(func));
    1383           6 :                     CATCH_REQUIRE(r);
    1384             : 
    1385           6 :                     ++f_t1_index;
    1386             :                 }
    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           2 :                     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             :                 }
    1397           6 :                 else if(field.f_name == "t2")
    1398             :                 {
    1399           4 :                     snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1400             :                                   &t2::process_hunk
    1401           2 :                                 , &f_t2
    1402             :                                 , std::placeholders::_1
    1403           3 :                                 , std::placeholders::_2));
    1404           1 :                     bool const r(in.deserialize(func));
    1405           1 :                     CATCH_REQUIRE(r);
    1406             :                 }
    1407           5 :                 else if(field.f_name == "flower-color")
    1408             :                 {
    1409           2 :                     std::string value;
    1410           1 :                     in.read_data(value);
    1411           1 :                     CATCH_REQUIRE(value.length() == std::string("bluish").length());
    1412           1 :                     CATCH_REQUIRE(value == std::string("bluish"));
    1413             :                 }
    1414           4 :                 else if(field.f_name == "flower-height")
    1415             :                 {
    1416           2 :                     std::string value;
    1417           1 :                     in.read_data(value);
    1418           1 :                     CATCH_REQUIRE(value == std::string());
    1419             :                 }
    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           2 :                     std::string value;
    1431           1 :                     in.read_data(value);
    1432           1 :                     CATCH_REQUIRE(value.length() == std::string("red").length());
    1433           1 :                     CATCH_REQUIRE(value == std::string("red"));
    1434             :                 }
    1435           2 :                 else if(field.f_name == "dog-height")
    1436             :                 {
    1437           2 :                     std::string value;
    1438           1 :                     in.read_data(value);
    1439           1 :                     CATCH_REQUIRE(value == std::string());
    1440             :                 }
    1441           2 :                 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           2 :                     std::string value;
    1453           1 :                     in.read_data(value);
    1454           1 :                     CATCH_REQUIRE(value == std::string("green"));
    1455             :                 }
    1456             :                 else
    1457             :                 {
    1458           0 :                     CATCH_REQUIRE(field.f_name == "?unknown?");
    1459             :                 }
    1460             : 
    1461          15 :                 return true;
    1462             :             }
    1463             : 
    1464             :         private:
    1465           1 :             int                 f_count = rand();
    1466           1 :             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           2 :         c o;
    1474             : 
    1475           2 :         std::stringstream buffer;
    1476           1 :         snapdev::serializer out(buffer);
    1477             : 
    1478           2 :         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           2 :         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           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1499             :                       &c::process_hunk
    1500           2 :                     , &o
    1501             :                     , std::placeholders::_1
    1502           3 :                     , std::placeholders::_2));
    1503           1 :         bool const r(in.deserialize(func));
    1504           1 :         CATCH_REQUIRE(r);
    1505             :     }
    1506             :     CATCH_END_SECTION()
    1507          13 : }
    1508             : 
    1509             : 
    1510          16 : CATCH_TEST_CASE("brs_invalid", "[basic]")
    1511             : {
    1512          28 :     CATCH_START_SECTION("brs: name missing")
    1513             :     {
    1514           2 :         std::stringstream buffer;
    1515           1 :         snapdev::serializer out(buffer);
    1516             : 
    1517           2 :         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           1 :         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           1 :         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           1 :         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           1 :         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           1 :         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             :     }
    1562             :     CATCH_END_SECTION()
    1563             : 
    1564          28 :     CATCH_START_SECTION("brs: name too long")
    1565             :     {
    1566           2 :         std::stringstream buffer;
    1567           1 :         snapdev::serializer out(buffer);
    1568             : 
    1569           2 :         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           2 :         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         283 :         for(std::size_t idx(0); idx < max; ++idx)
    1581             :         {
    1582         282 :             name += rand() % 26 + 'a';
    1583             :         }
    1584             : 
    1585           1 :         char value = 33;
    1586             : 
    1587             :         // FIELD
    1588           1 :         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           1 :         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           1 :         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           2 :         std::string sub_name;
    1613           1 :         std::size_t const sub_max(std::numeric_limits<std::uint8_t>::max() + 1 + rand() % 200);
    1614         452 :         for(std::size_t idx(0); idx < sub_max; ++idx)
    1615             :         {
    1616         451 :             sub_name += rand() % 26 + 'a';
    1617             :         }
    1618             : 
    1619           1 :         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           1 :         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             :     }
    1632             :     CATCH_END_SECTION()
    1633             : 
    1634          28 :     CATCH_START_SECTION("brs: hunk too long")
    1635             :     {
    1636           2 :         std::stringstream buffer;
    1637           1 :         snapdev::serializer out(buffer);
    1638             : 
    1639           2 :         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          20 :             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          20 :             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          20 :             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             :     }
    1669             :     CATCH_END_SECTION()
    1670             : 
    1671          28 :     CATCH_START_SECTION("brs: empty input")
    1672             :     {
    1673           2 :         std::stringstream buffer;
    1674             : 
    1675           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1676             :                   snapdev::deserializer<std::stringstream>(buffer)
    1677             :                 , snapdev::brs_magic_missing
    1678             :                 , Catch::Matchers::ExceptionMessage(
    1679             :                           "brs_error: magic missing from the start of the buffer."));
    1680             :     }
    1681             :     CATCH_END_SECTION()
    1682             : 
    1683          28 :     CATCH_START_SECTION("brs: magic unrecognized")
    1684             :     {
    1685           2 :         std::stringstream buffer;
    1686             : 
    1687           1 :         buffer << 'G';  // pretend it's a GIF
    1688           1 :         buffer << 'I';
    1689           1 :         buffer << 'F';
    1690           1 :         buffer << '8';
    1691           1 :         buffer << '9';
    1692           1 :         buffer << 'a';
    1693             : 
    1694           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1695             :                   snapdev::deserializer<std::stringstream>(buffer)
    1696             :                 , snapdev::brs_magic_unsupported
    1697             :                 , Catch::Matchers::ExceptionMessage(
    1698             :                           "brs_error: magic unsupported."));
    1699             :     }
    1700             :     CATCH_END_SECTION()
    1701             : 
    1702          28 :     CATCH_START_SECTION("brs: unknown hunk type")
    1703             :     {
    1704           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    1729           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1730           2 :                       &processor::process_hunk
    1731             :                     , std::placeholders::_1
    1732           3 :                     , std::placeholders::_2));
    1733             : 
    1734           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1735             :                   in.deserialize(func)
    1736             :                 , snapdev::brs_unknown_type
    1737             :                 , Catch::Matchers::ExceptionMessage(
    1738             :                           "brs_error: read a field with an unknown type."));
    1739             :     }
    1740             :     CATCH_END_SECTION()
    1741             : 
    1742          28 :     CATCH_START_SECTION("brs: field missing name")
    1743             :     {
    1744           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    1769           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1770           2 :                       &processor::process_hunk
    1771             :                     , std::placeholders::_1
    1772           3 :                     , std::placeholders::_2));
    1773             : 
    1774           1 :         bool r(in.deserialize(func));
    1775           1 :         CATCH_REQUIRE_FALSE(r);
    1776             :     }
    1777             :     CATCH_END_SECTION()
    1778             : 
    1779          28 :     CATCH_START_SECTION("brs: field data mismatch reading")
    1780             :     {
    1781           2 :         std::stringstream buffer;
    1782             : 
    1783             :         // magic
    1784           1 :         buffer << 'B';
    1785           1 :         buffer << 'R';
    1786           1 :         buffer << 'L';
    1787           1 :         buffer << snapdev::BRS_VERSION;
    1788             : 
    1789             :         // size hunk
    1790             :         // type 3 is not recognized at the moment
    1791           1 :         std::uint32_t hunk(static_cast<std::uint32_t>((snapdev::TYPE_FIELD << 0) | (3 << 2) | (1 << 9)));
    1792           1 :         buffer.write(reinterpret_cast<char const *>(&hunk), 4);
    1793           1 :         char const * name("ABC");
    1794           1 :         buffer.write(name, 3);
    1795           1 :         std::uint8_t value(5);
    1796           1 :         buffer.write(reinterpret_cast<char const *>(&value), 1);
    1797             : 
    1798             :         struct processor
    1799             :         {
    1800           1 :             static bool process_hunk(
    1801             :                           snapdev::deserializer<std::stringstream> & in
    1802             :                         , snapdev::field_t const & field)
    1803             :             {
    1804           1 :                 CATCH_REQUIRE(field.f_name == "ABC");
    1805           1 :                 CATCH_REQUIRE(field.f_sub_name == std::string());
    1806           1 :                 CATCH_REQUIRE(field.f_index == -1);
    1807           1 :                 CATCH_REQUIRE(field.f_size == 1);
    1808             : 
    1809             :                 // reading the data other than the byte creates errors
    1810             :                 // (incorrect size--so you may be calling the read_data()
    1811             :                 // function with the wrong type)
    1812             :                 //
    1813             : 
    1814           1 :                 std::int16_t s;
    1815           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1816             :                           in.read_data(s)
    1817             :                         , snapdev::brs_logic_error
    1818             :                         , Catch::Matchers::ExceptionMessage(
    1819             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 2."));
    1820             : 
    1821           1 :                 std::uint16_t us;
    1822           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1823             :                           in.read_data(us)
    1824             :                         , snapdev::brs_logic_error
    1825             :                         , Catch::Matchers::ExceptionMessage(
    1826             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 2."));
    1827             : 
    1828           1 :                 std::int32_t i;
    1829           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1830             :                           in.read_data(i)
    1831             :                         , snapdev::brs_logic_error
    1832             :                         , Catch::Matchers::ExceptionMessage(
    1833             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 4."));
    1834             : 
    1835           1 :                 std::uint32_t ui;
    1836           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1837             :                           in.read_data(ui)
    1838             :                         , snapdev::brs_logic_error
    1839             :                         , Catch::Matchers::ExceptionMessage(
    1840             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 4."));
    1841             : 
    1842           1 :                 std::int64_t l;
    1843           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1844             :                           in.read_data(l)
    1845             :                         , snapdev::brs_logic_error
    1846             :                         , Catch::Matchers::ExceptionMessage(
    1847             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 8."));
    1848             : 
    1849           1 :                 std::uint64_t ul;
    1850           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1851             :                           in.read_data(ul)
    1852             :                         , snapdev::brs_logic_error
    1853             :                         , Catch::Matchers::ExceptionMessage(
    1854             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 8."));
    1855             : 
    1856           1 :                 float f;
    1857           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1858             :                           in.read_data(f)
    1859             :                         , snapdev::brs_logic_error
    1860             :                         , Catch::Matchers::ExceptionMessage(
    1861             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 4."));
    1862             : 
    1863           1 :                 double d;
    1864           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1865             :                           in.read_data(d)
    1866             :                         , snapdev::brs_logic_error
    1867             :                         , Catch::Matchers::ExceptionMessage(
    1868             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 8."));
    1869             : 
    1870           1 :                 long double ld;
    1871           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1872             :                           in.read_data(ld)
    1873             :                         , snapdev::brs_logic_error
    1874             :                         , Catch::Matchers::ExceptionMessage(
    1875             :                                   "brs_logic_error: hunk size is 1, but you are trying to read 16."));
    1876             : 
    1877           2 :                 std::vector<std::int64_t> vl;
    1878           1 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1879             :                           in.read_data(vl)
    1880             :                         , snapdev::brs_logic_error
    1881             :                         , Catch::Matchers::ExceptionMessage(
    1882             :                                   "brs_logic_error: hunk size (1) is not a multiple of the vector item size: 8."));
    1883             : 
    1884           1 :                 std::uint8_t b(0);
    1885           1 :                 CATCH_REQUIRE(in.read_data(b));
    1886           1 :                 CATCH_REQUIRE(b == 5);
    1887             : 
    1888           2 :                 return true;
    1889             :             }
    1890             :         };
    1891             : 
    1892           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    1893           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1894           2 :                       &processor::process_hunk
    1895             :                     , std::placeholders::_1
    1896           3 :                     , std::placeholders::_2));
    1897             : 
    1898           1 :         bool r(in.deserialize(func));
    1899           1 :         CATCH_REQUIRE(r);
    1900             :     }
    1901             :     CATCH_END_SECTION()
    1902             : 
    1903          28 :     CATCH_START_SECTION("brs: missing array index")
    1904             :     {
    1905           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    1930           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1931           2 :                       &processor::process_hunk
    1932             :                     , std::placeholders::_1
    1933           3 :                     , std::placeholders::_2));
    1934             : 
    1935           1 :         bool r(in.deserialize(func));
    1936           1 :         CATCH_REQUIRE_FALSE(r);
    1937             :     }
    1938             :     CATCH_END_SECTION()
    1939             : 
    1940          28 :     CATCH_START_SECTION("brs: missing array field name")
    1941             :     {
    1942           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    1969           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    1970           2 :                       &processor::process_hunk
    1971             :                     , std::placeholders::_1
    1972           3 :                     , std::placeholders::_2));
    1973             : 
    1974           1 :         bool r(in.deserialize(func));
    1975           1 :         CATCH_REQUIRE_FALSE(r);
    1976             :     }
    1977             :     CATCH_END_SECTION()
    1978             : 
    1979          28 :     CATCH_START_SECTION("brs: missing map sub-name length")
    1980             :     {
    1981           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    2006           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    2007           2 :                       &processor::process_hunk
    2008             :                     , std::placeholders::_1
    2009           3 :                     , std::placeholders::_2));
    2010             : 
    2011           1 :         bool r(in.deserialize(func));
    2012           1 :         CATCH_REQUIRE_FALSE(r);
    2013             :     }
    2014             :     CATCH_END_SECTION()
    2015             : 
    2016          28 :     CATCH_START_SECTION("brs: map sub-name length is zero")
    2017             :     {
    2018           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    2045           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    2046           2 :                       &processor::process_hunk
    2047             :                     , std::placeholders::_1
    2048           3 :                     , std::placeholders::_2));
    2049             : 
    2050           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2051             :                   in.deserialize(func)
    2052             :                 , snapdev::brs_map_name_cannot_be_empty
    2053             :                 , Catch::Matchers::ExceptionMessage(
    2054             :                           "brs_error: the length of a map's field name cannot be zero."));
    2055             :     }
    2056             :     CATCH_END_SECTION()
    2057             : 
    2058          28 :     CATCH_START_SECTION("brs: missing map sub-name")
    2059             :     {
    2060           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    2087           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    2088           2 :                       &processor::process_hunk
    2089             :                     , std::placeholders::_1
    2090           3 :                     , std::placeholders::_2));
    2091             : 
    2092           1 :         bool r(in.deserialize(func));
    2093           1 :         CATCH_REQUIRE_FALSE(r);
    2094             :     }
    2095             :     CATCH_END_SECTION()
    2096             : 
    2097          28 :     CATCH_START_SECTION("brs: missing map name")
    2098             :     {
    2099           2 :         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           2 :         snapdev::deserializer<std::stringstream> in(buffer);
    2128           4 :         snapdev::deserializer<std::stringstream>::process_hunk_t func(std::bind(
    2129           2 :                       &processor::process_hunk
    2130             :                     , std::placeholders::_1
    2131           3 :                     , std::placeholders::_2));
    2132             : 
    2133           1 :         bool r(in.deserialize(func));
    2134           1 :         CATCH_REQUIRE_FALSE(r);
    2135             :     }
    2136             :     CATCH_END_SECTION()
    2137          20 : }
    2138             : 
    2139             : 
    2140             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13