LCOV - code coverage report
Current view: top level - src/test - util_string_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 96.6 % 207 200
Test Date: 2026-02-04 04:43:42 Functions: 100.0 % 31 31
Branches: 46.7 % 796 372

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <util/strencodings.h>
       6                 :             : #include <util/string.h>
       7                 :             : #include <vector>
       8                 :             : 
       9                 :             : #include <boost/test/unit_test.hpp>
      10                 :             : #include <test/util/setup_common.h>
      11                 :             : 
      12                 :             : using namespace util;
      13                 :             : using util::detail::CheckNumFormatSpecifiers;
      14                 :             : 
      15                 :             : BOOST_AUTO_TEST_SUITE(util_string_tests)
      16                 :             : 
      17                 :             : template <unsigned NumArgs>
      18                 :          42 : void TfmFormatZeroes(const std::string& fmt)
      19                 :             : {
      20                 :         124 :     std::apply([&](auto... args) {
      21                 :          42 :         (void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
      22                 :             :     }, std::array<int, NumArgs>{});
      23                 :          40 : }
      24                 :             : 
      25                 :             : // Helper to allow compile-time sanity checks while providing the number of
      26                 :             : // args directly. Normally PassFmt<sizeof...(Args)> would be used.
      27                 :             : template <unsigned NumArgs>
      28                 :          40 : void PassFmt(ConstevalFormatString<NumArgs> fmt)
      29                 :             : {
      30                 :             :     // Execute compile-time check again at run-time to get code coverage stats
      31   [ +  -  +  -  :          80 :     BOOST_CHECK_NO_THROW(CheckNumFormatSpecifiers<NumArgs>(fmt.fmt));
          +  -  -  -  -  
                      - ]
      32                 :             : 
      33                 :             :     // If ConstevalFormatString didn't throw above, make sure tinyformat doesn't
      34                 :             :     // throw either for the same format string and parameter count combination.
      35                 :             :     // Proves that we have some extent of protection from runtime errors
      36                 :             :     // (tinyformat may still throw for some type mismatches).
      37   [ +  -  +  -  :         120 :     BOOST_CHECK_NO_THROW(TfmFormatZeroes<NumArgs>(fmt.fmt));
          +  -  +  -  -  
                -  -  - ]
      38                 :          40 : }
      39                 :             : template <unsigned WrongNumArgs>
      40                 :          32 : void FailFmtWithError(const char* wrong_fmt, std::string_view error)
      41                 :             : {
      42   [ +  -  -  +  :          64 :     BOOST_CHECK_EXCEPTION(CheckNumFormatSpecifiers<WrongNumArgs>(wrong_fmt), const char*, HasReason{error});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
      43                 :          32 : }
      44                 :             : 
      45                 :           9 : std::vector<std::byte> StringToBuffer(const std::string& str)
      46                 :             : {
      47         [ -  + ]:           9 :     auto span = std::as_bytes(std::span(str));
      48                 :           9 :     return {span.begin(), span.end()};
      49                 :             : }
      50                 :             : 
      51   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(ConstevalFormatString_NumSpec)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      52                 :             : {
      53                 :           1 :     PassFmt<0>("");
      54                 :           1 :     PassFmt<0>("%%");
      55                 :           1 :     PassFmt<1>("%s");
      56                 :           1 :     PassFmt<1>("%c");
      57                 :           1 :     PassFmt<0>("%%s");
      58                 :           1 :     PassFmt<0>("s%%");
      59                 :           1 :     PassFmt<1>("%%%s");
      60                 :           1 :     PassFmt<1>("%s%%");
      61                 :           1 :     PassFmt<0>(" 1$s");
      62                 :           1 :     PassFmt<1>("%1$s");
      63                 :           1 :     PassFmt<1>("%1$s%1$s");
      64                 :           1 :     PassFmt<2>("%2$s");
      65                 :           1 :     PassFmt<2>("%2$s 4$s %2$s");
      66                 :           1 :     PassFmt<129>("%129$s 999$s %2$s");
      67                 :           1 :     PassFmt<1>("%02d");
      68                 :           1 :     PassFmt<1>("%+2s");
      69                 :           1 :     PassFmt<1>("%.6i");
      70                 :           1 :     PassFmt<1>("%5.2f");
      71                 :           1 :     PassFmt<1>("%5.f");
      72                 :           1 :     PassFmt<1>("%.f");
      73                 :           1 :     PassFmt<1>("%#x");
      74                 :           1 :     PassFmt<1>("%1$5i");
      75                 :           1 :     PassFmt<1>("%1$-5i");
      76                 :           1 :     PassFmt<1>("%1$.5i");
      77                 :             :     // tinyformat accepts almost any "type" spec, even '%', or '_', or '\n'.
      78                 :           1 :     PassFmt<1>("%123%");
      79                 :           1 :     PassFmt<1>("%123%s");
      80                 :           1 :     PassFmt<1>("%_");
      81                 :           1 :     PassFmt<1>("%\n");
      82                 :             : 
      83                 :           1 :     PassFmt<2>("%*c");
      84                 :           1 :     PassFmt<2>("%+*c");
      85                 :           1 :     PassFmt<2>("%.*f");
      86                 :           1 :     PassFmt<3>("%*.*f");
      87                 :           1 :     PassFmt<3>("%2$*3$d");
      88                 :           1 :     PassFmt<3>("%2$*3$.9d");
      89                 :           1 :     PassFmt<3>("%2$.*3$d");
      90                 :           1 :     PassFmt<3>("%2$9.*3$d");
      91                 :           1 :     PassFmt<3>("%2$+9.*3$d");
      92                 :           1 :     PassFmt<4>("%3$*2$.*4$f");
      93                 :             : 
      94                 :             :     // Make sure multiple flag characters "- 0+" are accepted
      95                 :           1 :     PassFmt<3>("'%- 0+*.*f'");
      96                 :           1 :     PassFmt<3>("'%1$- 0+*3$.*2$f'");
      97                 :             : 
      98                 :           1 :     auto err_mix{"Format specifiers must be all positional or all non-positional!"};
      99                 :           1 :     FailFmtWithError<1>("%s%1$s", err_mix);
     100                 :           1 :     FailFmtWithError<2>("%2$*d", err_mix);
     101                 :           1 :     FailFmtWithError<2>("%*2$d", err_mix);
     102                 :           1 :     FailFmtWithError<2>("%.*3$d", err_mix);
     103                 :           1 :     FailFmtWithError<2>("%2$.*d", err_mix);
     104                 :             : 
     105                 :           1 :     auto err_num{"Format specifier count must match the argument count!"};
     106                 :           1 :     FailFmtWithError<1>("", err_num);
     107                 :           1 :     FailFmtWithError<0>("%s", err_num);
     108                 :           1 :     FailFmtWithError<2>("%s", err_num);
     109                 :           1 :     FailFmtWithError<0>("%1$s", err_num);
     110                 :           1 :     FailFmtWithError<2>("%1$s", err_num);
     111                 :           1 :     FailFmtWithError<1>("%*c", err_num);
     112                 :             : 
     113                 :           1 :     auto err_0_pos{"Positional format specifier must have position of at least 1"};
     114                 :           1 :     FailFmtWithError<1>("%$s", err_0_pos);
     115                 :           1 :     FailFmtWithError<1>("%$", err_0_pos);
     116                 :           1 :     FailFmtWithError<0>("%0$", err_0_pos);
     117                 :           1 :     FailFmtWithError<0>("%0$s", err_0_pos);
     118                 :           1 :     FailFmtWithError<2>("%2$*$d", err_0_pos);
     119                 :           1 :     FailFmtWithError<2>("%2$*0$d", err_0_pos);
     120                 :           1 :     FailFmtWithError<3>("%3$*2$.*$f", err_0_pos);
     121                 :           1 :     FailFmtWithError<3>("%3$*2$.*0$f", err_0_pos);
     122                 :             : 
     123                 :           1 :     auto err_term{"Format specifier incorrectly terminated by end of string"};
     124                 :           1 :     FailFmtWithError<1>("%", err_term);
     125                 :           1 :     FailFmtWithError<1>("%9", err_term);
     126                 :           1 :     FailFmtWithError<1>("%9.", err_term);
     127                 :           1 :     FailFmtWithError<1>("%9.9", err_term);
     128                 :           1 :     FailFmtWithError<1>("%*", err_term);
     129                 :           1 :     FailFmtWithError<1>("%+*", err_term);
     130                 :           1 :     FailFmtWithError<1>("%.*", err_term);
     131                 :           1 :     FailFmtWithError<1>("%9.*", err_term);
     132                 :           1 :     FailFmtWithError<1>("%1$", err_term);
     133                 :           1 :     FailFmtWithError<1>("%1$9", err_term);
     134                 :           1 :     FailFmtWithError<2>("%1$*2$", err_term);
     135                 :           1 :     FailFmtWithError<2>("%1$.*2$", err_term);
     136                 :           1 :     FailFmtWithError<2>("%1$9.*2$", err_term);
     137                 :             : 
     138                 :             :     // Non-parity between tinyformat and ConstevalFormatString.
     139                 :             :     // tinyformat throws but ConstevalFormatString does not.
     140   [ +  -  -  +  :           2 :     BOOST_CHECK_EXCEPTION(tfm::format(ConstevalFormatString<1>{"%n"}, 0), tfm::format_error,
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     141                 :             :         HasReason{"tinyformat: %n conversion spec not supported"});
     142   [ +  -  -  +  :           2 :     BOOST_CHECK_EXCEPTION(tfm::format(ConstevalFormatString<2>{"%*s"}, "hi", "hi"), tfm::format_error,
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     143                 :             :         HasReason{"tinyformat: Cannot convert from argument type to integer for use as variable width or precision"});
     144   [ +  -  -  +  :           2 :     BOOST_CHECK_EXCEPTION(tfm::format(ConstevalFormatString<2>{"%.*s"}, "hi", "hi"), tfm::format_error,
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     145                 :             :         HasReason{"tinyformat: Cannot convert from argument type to integer for use as variable width or precision"});
     146                 :             : 
     147                 :             :     // Ensure that tinyformat throws if format string contains wrong number
     148                 :             :     // of specifiers. PassFmt relies on this to verify tinyformat successfully
     149                 :             :     // formats the strings, and will need to be updated if tinyformat is changed
     150                 :             :     // not to throw on failure.
     151   [ +  -  +  -  :           3 :     BOOST_CHECK_EXCEPTION(TfmFormatZeroes<2>("%s"), tfm::format_error,
          -  +  -  -  -  
          -  -  +  +  -  
             +  -  +  - ]
     152                 :             :         HasReason{"tinyformat: Not enough conversion specifiers in format string"});
     153   [ +  -  +  -  :           3 :     BOOST_CHECK_EXCEPTION(TfmFormatZeroes<1>("%s %s"), tfm::format_error,
          -  +  -  -  -  
          -  -  +  +  -  
             +  -  +  - ]
     154                 :             :         HasReason{"tinyformat: Too many conversion specifiers in format string"});
     155                 :           1 : }
     156                 :             : 
     157   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(ascii_case_insensitive_key_equal_test)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     158                 :             : {
     159                 :           1 :     AsciiCaseInsensitiveKeyEqual cmp;
     160   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("A", "B"));
     161   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("A", "b"));
     162   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("a", "B"));
     163   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("B", "A"));
     164   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("B", "a"));
     165   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("b", "A"));
     166   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("A", "AA"));
     167   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("A-A", "a-a"));
     168   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("A", "A"));
     169   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("A", "a"));
     170   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("a", "a"));
     171   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("B", "b"));
     172   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("ab", "aB"));
     173   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("Ab", "aB"));
     174   [ +  -  +  - ]:           2 :     BOOST_CHECK(cmp("AB", "ab"));
     175                 :             : 
     176                 :             :     // Use a character with value > 127
     177                 :             :     // to ensure we don't trigger implicit-integer-sign-change
     178   [ +  -  +  - ]:           2 :     BOOST_CHECK(!cmp("a", "\xe4"));
     179                 :           1 : }
     180                 :             : 
     181   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(ascii_case_insensitive_hash_test)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     182                 :             : {
     183                 :           1 :     AsciiCaseInsensitiveHash hsh;
     184         [ +  - ]:           1 :     BOOST_CHECK_NE(hsh("A"), hsh("B"));
     185         [ +  - ]:           1 :     BOOST_CHECK_NE(hsh("AA"), hsh("A"));
     186         [ +  - ]:           1 :     BOOST_CHECK_EQUAL(hsh("A"), hsh("a"));
     187         [ +  - ]:           1 :     BOOST_CHECK_EQUAL(hsh("Ab"), hsh("aB"));
     188         [ +  - ]:           1 :     BOOST_CHECK_EQUAL(hsh("A\xfe"), hsh("a\xfe"));
     189                 :           1 : }
     190                 :             : 
     191   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(line_reader_test)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     192                 :             : {
     193                 :           1 :     {
     194                 :             :         // Check three lines terminated by \n and \r\n, trimming whitespace
     195         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("once upon a time\n there was a dog \r\nwho liked food\n")};
     196   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/128);
     197         [ +  - ]:           1 :         std::optional<std::string> line1{reader.ReadLine()};
     198   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.Remaining(), 34);
                   +  - ]
     199         [ +  - ]:           1 :         std::optional<std::string> line2{reader.ReadLine()};
     200   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.Remaining(), 15);
                   +  - ]
     201         [ +  - ]:           1 :         std::optional<std::string> line3{reader.ReadLine()};
     202         [ +  - ]:           1 :         std::optional<std::string> line4{reader.ReadLine()};
     203   [ +  -  +  -  :           2 :         BOOST_CHECK(line1);
                   +  - ]
     204   [ +  -  +  -  :           2 :         BOOST_CHECK(line2);
                   +  - ]
     205   [ +  -  +  -  :           2 :         BOOST_CHECK(line3);
                   +  - ]
     206   [ +  -  +  -  :           2 :         BOOST_CHECK(!line4);
                   +  - ]
     207   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(line1.value(), "once upon a time");
                   +  - ]
     208   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(line2.value(), "there was a dog");
                   +  - ]
     209   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(line3.value(), "who liked food");
                   +  - ]
     210                 :           1 :     }
     211                 :           1 :     {
     212                 :             :         // Do not exceed max_line_length + 1 while searching for \n
     213                 :             :         // Test with 22-character line + \n + 23-character line + \n
     214         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("once upon a time there\nwas a dog who liked tea\n")};
     215                 :             : 
     216   [ -  +  +  - ]:           1 :         LineReader reader1(input, /*max_line_length=*/22);
     217                 :             :         // First line is exactly the length of max_line_length
     218   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader1.ReadLine(), "once upon a time there");
                   +  - ]
     219                 :             :         // Second line is +1 character too long
     220   [ +  -  -  +  :           2 :         BOOST_CHECK_EXCEPTION(reader1.ReadLine(), std::runtime_error, HasReason{"max_line_length exceeded by LineReader"});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     221                 :             : 
     222                 :             :         // Increase max_line_length by 1
     223   [ -  +  +  - ]:           1 :         LineReader reader2(input, /*max_line_length=*/23);
     224                 :             :         // Both lines fit within limit
     225   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader2.ReadLine(), "once upon a time there");
                   +  - ]
     226   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader2.ReadLine(), "was a dog who liked tea");
                   +  - ]
     227                 :             :         // End of buffer reached
     228   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader2.ReadLine());
                   +  - ]
     229                 :           0 :     }
     230                 :           1 :     {
     231                 :             :         // Empty lines are empty
     232         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("\n")};
     233   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1024);
     234   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLine(), "");
                   +  - ]
     235   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader.ReadLine());
                   +  - ]
     236                 :           0 :     }
     237                 :           1 :     {
     238                 :             :         // Empty buffers are null
     239         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("")};
     240   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1024);
     241   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader.ReadLine());
                   +  - ]
     242                 :           0 :     }
     243                 :           1 :     {
     244                 :             :         // Even one character is too long, if it's not \n
     245         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("ab\n")};
     246   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1);
     247                 :             :         // First line is +1 character too long
     248   [ +  -  -  +  :           2 :         BOOST_CHECK_EXCEPTION(reader.ReadLine(), std::runtime_error, HasReason{"max_line_length exceeded by LineReader"});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     249                 :           0 :     }
     250                 :           1 :     {
     251         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("a\nb\n")};
     252   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1);
     253   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLine(), "a");
                   +  - ]
     254   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLine(), "b");
                   +  - ]
     255   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader.ReadLine());
                   +  - ]
     256                 :           0 :     }
     257                 :           1 :     {
     258                 :             :         // If ReadLine fails, the iterator is reset and we can ReadLength instead
     259         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("a\nbaboon\n")};
     260   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1);
     261   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLine(), "a");
                   +  - ]
     262                 :             :         // "baboon" is too long
     263   [ +  -  -  +  :           2 :         BOOST_CHECK_EXCEPTION(reader.ReadLine(), std::runtime_error, HasReason{"max_line_length exceeded by LineReader"});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     264   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(1), "b");
                   +  - ]
     265   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(1), "a");
                   +  - ]
     266   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(2), "bo");
                   +  - ]
     267                 :             :         // "on" is too long
     268   [ +  -  -  +  :           2 :         BOOST_CHECK_EXCEPTION(reader.ReadLine(), std::runtime_error, HasReason{"max_line_length exceeded by LineReader"});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     269   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(1), "o");
                   +  - ]
     270   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLine(), "n"); // now the remainder of the buffer fits in one line
                   +  - ]
     271   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader.ReadLine());
                   +  - ]
     272                 :           0 :     }
     273                 :           1 :     {
     274                 :             :         // The end of the buffer (EOB) does not count as end of line \n
     275         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("once upon a time there")};
     276                 :             : 
     277   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/22);
     278                 :             :         // First line is exactly the length of max_line_length, but that doesn't matter because \n is missing
     279   [ +  -  +  -  :           2 :         BOOST_CHECK(!reader.ReadLine());
             +  -  +  - ]
     280                 :             :         // Data can still be read using ReadLength
     281   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(22), "once upon a time there");
                   +  - ]
     282                 :             :         // End of buffer reached
     283   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.Remaining(), 0);
                   +  - ]
     284                 :           0 :     }
     285                 :           1 :     {
     286                 :             :         // Read specific number of bytes regardless of max_line_length or \n unless buffer is too short
     287         [ +  - ]:           1 :         const std::vector<std::byte> input{StringToBuffer("once upon a time\n there was a dog \r\nwho liked food")};
     288   [ -  +  +  - ]:           1 :         LineReader reader(input, /*max_line_length=*/1);
     289   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(0), "");
                   +  - ]
     290   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(3), "onc");
                   +  - ]
     291   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(8), "e upon a");
                   +  - ]
     292   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(8), " time\n t");
                   +  - ]
     293   [ +  -  -  +  :           2 :         BOOST_CHECK_EXCEPTION(reader.ReadLength(128), std::runtime_error, HasReason{"Not enough data in buffer"});
          -  -  -  -  -  
          +  +  -  +  -  
                   +  - ]
     294                 :             :         // After the error the iterator is reset so we can try again
     295   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.ReadLength(31), "here was a dog \r\nwho liked food");
                   +  - ]
     296                 :             :         // End of buffer reached
     297   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(reader.Remaining(), 0);
                   +  - ]
     298                 :           1 :     }
     299                 :           1 : }
     300                 :             : 
     301                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1