From 9abbdba8e78eea47777bbfc5a159319c74dd18b9 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Thu, 13 Aug 2026 18:42:06 +0300 Subject: [PATCH 1/5] more test coverage for key_value_pair --- test/object.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/object.cpp b/test/object.cpp index efd88cae0..cb0330c01 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -272,6 +272,17 @@ class object_test { object o; } + { + key_value_pair kp("a", "b"); + } + { + // this test is mostly for getting more test coverage + monotonic_resource mr; + std::pair p("k", "v"); + key_value_pair kp(p, &mr); + BOOST_TEST(kp.key() == "k"); + BOOST_TEST(kp.value() == "v"); + } } void From 2ec9153f83a921dfd23f7a5f0c74d7a4e77f97d2 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Thu, 13 Aug 2026 19:16:23 +0300 Subject: [PATCH 2/5] exclude unreachable lines from coverage --- include/boost/json/basic_parser_impl.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/boost/json/basic_parser_impl.hpp b/include/boost/json/basic_parser_impl.hpp index b906b6aaf..071a224c9 100644 --- a/include/boost/json/basic_parser_impl.hpp +++ b/include/boost/json/basic_parser_impl.hpp @@ -434,7 +434,7 @@ parse_comment(const char* p, st_.pop(st); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::com1: goto do_com1; case state::com2: goto do_com2; case state::com3: goto do_com3; @@ -723,7 +723,7 @@ resume_value(const char* p, st_.peek(st); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::lit1: return parse_literal(p, detail::literals_c() ); @@ -859,7 +859,7 @@ parse_literal(const char* p, Literal) } else { - BOOST_JSON_UNREACHABLE(); + BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE } cs += sz; @@ -947,7 +947,7 @@ parse_literal(const char* p, Literal) ec_))) return fail(cs.begin()); break; - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE } cs += size; @@ -977,7 +977,7 @@ parse_string(const char* p, st_.pop(total); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::str2: goto do_str2; case state::str8: goto do_str8; case state::str1: break; @@ -1191,7 +1191,7 @@ parse_escaped( st_.pop(st); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::str3: goto do_str3; case state::str4: goto do_str4; case state::str5: goto do_str5; @@ -1739,7 +1739,7 @@ parse_object(const char* p, st_.pop(size); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::obj1: goto do_obj1; case state::obj2: goto do_obj2; case state::obj3: goto do_obj3; @@ -1908,7 +1908,7 @@ parse_array(const char* p, st_.pop(size); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::arr1: goto do_arr1; case state::arr2: goto do_arr2; case state::arr3: goto do_arr3; @@ -2158,7 +2158,7 @@ parse_number(const char* p, st_.pop(st); switch(st) { - default: BOOST_JSON_UNREACHABLE(); + default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE case state::num1: goto do_num1; case state::num2: goto do_num2; case state::num3: goto do_num3; From 6ad6097646de314b1edb41e94a13f692afa7a386 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Mon, 17 Aug 2026 15:22:50 +0300 Subject: [PATCH 3/5] more parser coverage --- test/basic_parser.cpp | 49 ++++++++++++- test/limits.cpp | 158 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 187 insertions(+), 20 deletions(-) diff --git a/test/basic_parser.cpp b/test/basic_parser.cpp index 82ac57f67..0f5ba952a 100644 --- a/test/basic_parser.cpp +++ b/test/basic_parser.cpp @@ -594,8 +594,8 @@ class basic_parser_test TEST_GOOD("1000000000000000000000000.000000000001"); TEST_GOOD("1000000000000000000000000.0e1 "); TEST_GOOD("1000000000000000000000000.0 "); - TEST_GOOD("1000000000.1000000000 "); + TEST_GOOD("100000000000000000000e+2147483647"); TEST_BAD(""); TEST_BAD("- "); @@ -1752,6 +1752,52 @@ class basic_parser_test #pragma warning(pop) #endif + struct null_handler + { + constexpr static std::size_t max_object_size = std::size_t(-1); + constexpr static std::size_t max_array_size = std::size_t(-1); + constexpr static std::size_t max_key_size = std::size_t(-1); + constexpr static std::size_t max_string_size = std::size_t(-1); + + bool on_document_begin( system::error_code& ) { return true; } + bool on_document_end( system::error_code& ) { return true; } + bool on_object_begin( system::error_code& ) { return true; } + bool on_object_end( std::size_t, system::error_code& ) { return true; } + bool on_array_begin( system::error_code& ) { return true; } + bool on_array_end( std::size_t, system::error_code& ) { return true; } + bool on_key_part( string_view, std::size_t, system::error_code& ) { return true; } + bool on_key( string_view, std::size_t, system::error_code& ) { return true; } + bool on_string_part( string_view, std::size_t, system::error_code& ) { return true; } + bool on_string( string_view, std::size_t, system::error_code& ) { return true; } + bool on_number_part( string_view, system::error_code&) { return true; } + bool on_int64( std::int64_t, string_view, system::error_code& ) { return true; } + bool on_uint64( std::uint64_t, string_view, system::error_code& ) { return true; } + bool on_double( double, string_view, system::error_code& ) { return true; } + bool on_bool( bool, system::error_code& ) { return true; } + bool on_null( system::error_code& ) { return true; } + bool on_comment_part( string_view, system::error_code& ) { return true; } + bool on_comment( string_view, system::error_code& ) { return true; } + }; + + void + testManualFail() + { + basic_parser p({}); + p.fail( system::error_code() ); + BOOST_TEST( !p.done() ); + BOOST_TEST( p.last_error() == error::incomplete ); + BOOST_TEST( p.last_error().has_location() ); + + p.reset(); + + system::error_code ec; + p.write_some(false, "null", 4, ec); + BOOST_TEST( p.done() ); + p.fail( make_error_code(error::array_too_large) ); + BOOST_TEST( !p.done() ); + BOOST_TEST( p.last_error() == error::array_too_large ); + } + void run() { @@ -1776,6 +1822,7 @@ class basic_parser_test testNumberLiteral(); testStickyErrors(); testStdTypes(); + testManualFail(); } }; diff --git a/test/limits.cpp b/test/limits.cpp index df836cc3b..408e47eb0 100644 --- a/test/limits.cpp +++ b/test/limits.cpp @@ -220,6 +220,52 @@ class limits_test BOOST_TEST(ec.has_location()); } + // string in parser, fails at the beginning of the 2nd escape sequence + { + stream_parser p; + system::error_code ec; + p.write_some("\"", 1, ec); + BOOST_TEST( !ec.failed() ); + for(std::size_t i = 0; i < string::max_size(); ++i) + { + p.write_some("0", 1, ec); + } + p.write_some("\\n\\", 3, ec); + BOOST_TEST(ec == error::string_too_large); + BOOST_TEST(ec.has_location()); + } + + // string in parser, fails at the beginning of the 2nd + // (unicode) escape sequence + { + stream_parser p; + system::error_code ec; + p.write_some("\"", 1, ec); + BOOST_TEST( !ec.failed() ); + for(std::size_t i = 0; i < string::max_size(); ++i) + { + p.write_some("0", 1, ec); + } + p.write_some("\\n\\u", 4, ec); + BOOST_TEST(ec == error::string_too_large); + BOOST_TEST(ec.has_location()); + } + + // string in parser, fails after the last escape + { + stream_parser p; + system::error_code ec; + p.write_some("\"", 1, ec); + BOOST_TEST( !ec.failed() ); + for(std::size_t i = 0; i < string::max_size(); ++i) + { + p.write_some("0", 1, ec); + } + p.write_some("\\n0", 3, ec); + BOOST_TEST(ec == error::string_too_large); + BOOST_TEST(ec.has_location()); + } + // key in parser { stream_parser p; @@ -405,30 +451,104 @@ class limits_test testNumber() { // very long floating point number - std::array buffer; - buffer.fill('0'); - buffer.data()[1] = '.'; + { + std::array buffer; + buffer.fill('0'); + buffer.data()[1] = '.'; - parse_options precise; - precise.numbers = number_precision::precise; + parse_options precise; + precise.numbers = number_precision::precise; - stream_parser p( {}, precise ); - system::error_code ec; - p.write( buffer.data(), 1, ec ); - BOOST_TEST_THROWS_WITH_LOCATION( - p.write( buffer.data() + 1, buffer.size() - 1, ec )); - BOOST_TEST( !ec ); + stream_parser p( {}, precise ); + system::error_code ec; + p.write( buffer.data(), 1, ec ); + BOOST_TEST_THROWS_WITH_LOCATION( + p.write( buffer.data() + 1, buffer.size() - 1, ec )); + BOOST_TEST( !ec ); + + // now we make the number one character shorter + p.reset(); + p.write( buffer.data(), 1, ec ); + BOOST_TEST( !ec ); + + p.write( buffer.data() + 1, buffer.size() - 2, ec ); + BOOST_TEST( !ec ); + + auto jv = p.release(); + BOOST_TEST( jv.as_double() == 0 ); + } + +#ifndef BOOST_JSON_NO_LONG_TESTS + // number with too many digits before decimal point + { + stream_parser p; + system::error_code ec; + std::string number(static_cast(INT_MAX) + 19, '1'); + p.write_some(number, ec); + BOOST_TEST( !ec.failed() ); + + p.write_some("1", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); + } - // now we make the number one character shorter - p.reset(); - p.write( buffer.data(), 1, ec ); - BOOST_TEST( !ec ); + // number with too many digits after decimal point + { + stream_parser p; + system::error_code ec; + p.write_some("0.", 2, ec); + BOOST_TEST( !ec.failed() ); + std::string number(static_cast(INT_MAX), '0'); + p.write_some(number, ec); + BOOST_TEST( !ec.failed() ); + + p.write_some("0", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); + } - p.write( buffer.data() + 1, buffer.size() - 2, ec ); - BOOST_TEST( !ec ); + // number with non-zero mantissa, many digits after decimal point, + // and overflowing negative exponent + { + stream_parser p; + system::error_code ec; + p.write_some("0.", 2, ec); + BOOST_TEST( !ec.failed() ); + std::string number(static_cast(INT_MAX) - 308, '0'); + p.write_some(number, ec); + BOOST_TEST( !ec.failed() ); + p.write_some("1e-", 3, ec); + BOOST_TEST( !ec.failed() ); + p.write_some("2147483647", 10, ec); + BOOST_TEST( !ec.failed() ); + // 0.(INT_MAX - 308 zeroes)1e-2147483647 + + p.write_some(" ", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); + } - auto jv = p.release(); - BOOST_TEST( jv.as_double() == 0 ); + // number with non-zero mantissa, many digits before decimal point, + // and overflowing positive exponent + { + stream_parser p; + system::error_code ec; + p.write_some("1", 1, ec); + BOOST_TEST( !ec.failed() ); + std::string number(static_cast(INT_MAX) - 289, '0'); + p.write_some(number, ec); + BOOST_TEST( !ec.failed() ); + p.write_some("1e+", 3, ec); + BOOST_TEST( !ec.failed() ); + p.write_some("2147483647", 10, ec); + BOOST_TEST( !ec.failed() ); + // 1(INT_MAX - 289 zeroes)1e+2147483647 + + p.write_some(" ", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); + } +#endif // BOOST_JSON_NO_LONG_TESTS } void From 8ada8b73545677cf621e373d70285bf131d5ca52 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Tue, 18 Aug 2026 18:06:45 +0300 Subject: [PATCH 4/5] memory resource coverage --- test/monotonic_resource.cpp | 8 ++++++++ test/null_resource.cpp | 4 ++-- test/static_resource.cpp | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/test/monotonic_resource.cpp b/test/monotonic_resource.cpp index d682b9350..389a17544 100644 --- a/test/monotonic_resource.cpp +++ b/test/monotonic_resource.cpp @@ -186,6 +186,14 @@ class monotonic_resource_test (void)mr.allocate(10,1); } + // equality comparison + { + monotonic_resource mr1; + monotonic_resource mr2; + BOOST_TEST(mr1 != mr2); + BOOST_TEST(mr1 == mr1); + } + // coverage { monotonic_resource mr(std::size_t(-1)-2); diff --git a/test/null_resource.cpp b/test/null_resource.cpp index 71cb479cd..d80de063e 100644 --- a/test/null_resource.cpp +++ b/test/null_resource.cpp @@ -30,8 +30,8 @@ class null_resource_test char buf[128]; // no-op mr.deallocate(&buf[0], 128); - BOOST_TEST( - mr == *get_null_resource()); + BOOST_TEST( mr == *get_null_resource() ); + BOOST_TEST( mr.is_equal(*get_null_resource()) ); } void diff --git a/test/static_resource.cpp b/test/static_resource.cpp index 5cae9a8ee..d5c3d1dc1 100644 --- a/test/static_resource.cpp +++ b/test/static_resource.cpp @@ -118,6 +118,22 @@ class static_resource_test mr.release(); (void)mr.allocate(10,1); } + + // misc + { + unsigned char b1[1]; + static_resource mr1(b1, 1); + + unsigned char b2[2]; + static_resource mr2(b2, 1); + + BOOST_TEST(mr1 != mr2); + BOOST_TEST(mr1 == mr1); + + // this is for higher coverage + auto const ptr = mr1.allocate(1, 1); + mr1.deallocate(ptr, 1); + } } void From ff8301b967e4e50671aa7055d16a424b69cf2b88 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Tue, 18 Aug 2026 18:44:33 +0300 Subject: [PATCH 5/5] some coverage false negatives are excluded --- include/boost/json/detail/impl/default_resource.ipp | 3 +-- include/boost/json/impl/parse.ipp | 4 ++-- include/boost/json/value_from.hpp | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/boost/json/detail/impl/default_resource.ipp b/include/boost/json/detail/impl/default_resource.ipp index 4eee8304d..0e85b1541 100644 --- a/include/boost/json/detail/impl/default_resource.ipp +++ b/include/boost/json/detail/impl/default_resource.ipp @@ -31,8 +31,7 @@ default_resource::instance_; // this is here so that ~memory_resource // is emitted in the library instead of // the user's TU. -default_resource:: -~default_resource() = default; +default_resource::~default_resource() = default; // LCOV_EXCL_LINE void* default_resource:: diff --git a/include/boost/json/impl/parse.ipp b/include/boost/json/impl/parse.ipp index f7c218905..067acda03 100644 --- a/include/boost/json/impl/parse.ipp +++ b/include/boost/json/impl/parse.ipp @@ -48,7 +48,7 @@ parse( value result = parse(s, jec, std::move(sp), opt); ec = jec; return result; -} +} // LCOV_EXCL_LINE value parse( @@ -114,7 +114,7 @@ parse( value result = parse(is, jec, std::move(sp), opt); ec = jec; return result; -} +} // LCOV_EXCL_LINE value parse( diff --git a/include/boost/json/value_from.hpp b/include/boost/json/value_from.hpp index 984c32a74..9ab286532 100644 --- a/include/boost/json/value_from.hpp +++ b/include/boost/json/value_from.hpp @@ -124,7 +124,7 @@ value_from( value jv(std::move(sp)); value_from( static_cast(t), ctx, jv ); return jv; -} +} // LCOV_EXCL_LINE /// Overload template