Repository: bitcoin/bitcoin
File: src/test/util_string_tests.cpp (C++)

Code before:
    AsciiCaseInsensitiveHash hsh;
    BOOST_CHECK_NE(hsh("A"), hsh("B"));
    BOOST_CHECK_NE(hsh("AA"), hsh("A"));
    BOOST_CHECK_EQUAL(hsh("A"), hsh("a"));
    BOOST_CHECK_EQUAL(hsh("Ab"), hsh("aB"));
}

BOOST_AUTO_TEST_CASE(line_reader_test)
{
    {
        // Check three lines terminated by \n, \r\n, and end of buffer, trimming whitespace
        const std::vector<std::byte> input{StringToBuffer("once upon a time\n there was a dog \r\nwho liked food")};
        LineReader reader(input, /*max_read=*/128);
        std::optional<std::string> line1{reader.ReadLine()};
        BOOST_CHECK_EQUAL(reader.Left(), 33);
        std::optional<std::string> line2{reader.ReadLine()};
        BOOST_CHECK_EQUAL(reader.Left(), 14);
        std::optional<std::string> line3{reader.ReadLine()};
        std::optional<std::string> line4{reader.ReadLine()};
        BOOST_CHECK(line1);
        BOOST_CHECK(line2);
        BOOST_CHECK(line3);
        BOOST_CHECK(!line4);
        BOOST_CHECK_EQUAL(line1.value(), "once upon a time");
        BOOST_CHECK_EQUAL(line2.value(), "there was a dog");
        BOOST_CHECK_EQUAL(line3.value(), "who liked food");
    }
    {
        // Do not exceed max_read while searching for \n
        // Test with 22-character line + \n + 23-character line + \n
        const std::vector<std::byte> input{StringToBuffer("once upon a time there\nwas a dog who liked tea\n")};

        LineReader reader1(input, /*max_read=*/22);
        // First line is exactly the length of max_read
        BOOST_CHECK_EQUAL(reader1.ReadLine(), "once upon a time there");
        // Second line is +1 character too long
        BOOST_CHECK_THROW(reader1.ReadLine(), std::runtime_error);

        // Increase max_read by 1
        LineReader reader2(input, /*max_read=*/23);
        // Both lines fit within limit
        BOOST_CHECK_EQUAL(reader2.ReadLine(), "once upon a time there");
        BOOST_CHECK_EQUAL(reader2.ReadLine(), "was a dog who liked tea");
        // End of buffer reached
        BOOST_CHECK(!reader2.ReadLine());
    }
    {
        // Even one character is too long, if it's not \n
        const std::vector<std::byte> input{StringToBuffer("ab")};
        LineReader reader(input, /*max_read=*/1);
        // First line is +1 character too long

Review comment (refactor):
In 1d248166efe6cba330cfb14e652289f68c894652:

Tiny, non-blocking, idea to see if it makes sense to simplify the `LineReader` class.
(you can reinterpret `std::byte` to `char` in order to make it work with `std::istringstream`)

```c++
// Check three lines terminated by \n, \r\n, and end of buffer, trimming whitespace
const std::string input = "once upon a time\n there was a dog \r\nwho liked food";
std::istringstream stream(input);

std::string line1, line2, line3, line4;
std::getline(stream, line1);
std::getline(stream, line2);
std::getline(stream, line3);
BOOST_CHECK(!std::getline(stream, line4));

BOOST_CHECK_EQUAL(line1, "once upon a time");
BOOST_CHECK_EQUAL(line2, "there was a dog \r"); // TODO: trim whitespaces at the end.
BOOST_CHECK_EQUAL(line3, "who liked food");
```

Code after:
    // Use a character with value > 127
    // to ensure we don't trigger implicit-integer-sign-change
    BOOST_CHECK(!cmp("a", "\xe4"));
}

BOOST_AUTO_TEST_CASE(ascii_case_insensitive_hash_test)
{
    AsciiCaseInsensitiveHash hsh;
    BOOST_CHECK_NE(hsh("A"), hsh("B"));
    BOOST_CHECK_NE(hsh("AA"), hsh("A"));
    BOOST_CHECK_EQUAL(hsh("A"), hsh("a"));
    BOOST_CHECK_EQUAL(hsh("Ab"), hsh("aB"));
    BOOST_CHECK_EQUAL(hsh("A\xfe"), hsh("a\xfe"));
}

BOOST_AUTO_TEST_CASE(line_reader_test)
{
    {
        // Check three lines terminated by \n and \r\n, trimming whitespace
        const std::vector<std::byte> input{StringToBuffer("once upon a time\n there was a dog \r\nwho liked food\n")};
        LineReader reader(input, /*max_line_length=*/128);
        std::optional<std::string> line1{reader.ReadLine()};
        BOOST_CHECK_EQUAL(reader.Remaining(), 34);
        std::optional<std::string> line2{reader.ReadLine()};
        BOOST_CHECK_EQUAL(reader.Remaining(), 15);
        std::optional<std::string> line3{reader.ReadLine()};
        std::optional<std::string> line4{reader.ReadLine()};
        BOOST_CHECK(line1);
        BOOST_CHECK(line2);
        BOOST_CHECK(line3);
        BOOST_CHECK(!line4);
        BOOST_CHECK_EQUAL(line1.value(), "once upon a time");
        BOOST_CHECK_EQUAL(line2.value(), "there was a dog");
        BOOST_CHECK_EQUAL(line3.value(), "who liked food");
    }
    {
        // Do not exceed max_line_length + 1 while searching for \n
        // Test with 22-character line + \n + 23-character line + \n
        const std::vector<std::byte> input{StringToBuffer("once upon a time there\nwas a dog who liked tea\n")};

        LineReader reader1(input, /*max_line_length=*/22);
        // First line is exactly the length of max_line_length
        BOOST_CHECK_EQUAL(reader1.ReadLine(), "once upon a time there");
        // Second line is +1 character too long
        BOOST_CHECK_EXCEPTION(reader1.ReadLine(), std::runtime_error, HasReason{"max_line_length exceeded by LineReader"});

        // Increase max_line_length by 1
        LineReader reader2(input, /*max_line_length=*/23);
        // Both lines fit within limit
        BOOST_CHECK_EQUAL(reader2.ReadLine(), "once upon a time there");
        BOOST_CHECK_EQUAL(reader2.ReadLine(), "was a dog who liked tea");