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; 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/impl/value.ipp b/include/boost/json/impl/value.ipp index 34db8cc1d..d979258ab 100644 --- a/include/boost/json/impl/value.ipp +++ b/include/boost/json/impl/value.ipp @@ -225,30 +225,19 @@ value( // //---------------------------------------------------------- -value:: -value( - std::initializer_list init, - storage_ptr sp) +value::value(std::initializer_list init, storage_ptr sp) { - if(value_ref::maybe_object(init)) + if( value_ref::maybe_object(init) ) { - ::new(&obj_) object( - value_ref::make_object( - init, std::move(sp))); + ::new(&obj_) object( value_ref::make_object(init, std::move(sp)) ); + } + else if( init.size() == 1 ) + { + ::new(this) value( init.begin()->make_value(std::move(sp)) ); } else { - if( init.size() == 1 ) - { - ::new(this) value( - init.begin()->make_value( std::move(sp) )); - } - else - { - ::new(&arr_) array( - value_ref::make_array( - init, std::move(sp))); - } + ::new(&arr_) array( value_ref::make_array(init, std::move(sp)) ); } } diff --git a/include/boost/json/impl/value_ref.ipp b/include/boost/json/impl/value_ref.ipp index 99e75af0f..1b1b08d38 100644 --- a/include/boost/json/impl/value_ref.ipp +++ b/include/boost/json/impl/value_ref.ipp @@ -24,18 +24,6 @@ value() const return make_value({}); } -value -value_ref:: -from_init_list( - void const* p, - storage_ptr sp) -{ - return make_value( - *reinterpret_cast< - init_list const*>(p), - std::move(sp)); -} - bool value_ref:: is_key_value_pair() const noexcept @@ -97,11 +85,11 @@ make_value( case what::func: return f_.f(f_.p, std::move(sp)); - + case what::strfunc: return f_.f(f_.p, std::move(sp)); - + case what::cfunc: return cf_.f(cf_.p, std::move(sp)); 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 diff --git a/include/boost/json/value_ref.hpp b/include/boost/json/value_ref.hpp index e3137a308..22e63f9a2 100644 --- a/include/boost/json/value_ref.hpp +++ b/include/boost/json/value_ref.hpp @@ -431,13 +431,6 @@ class value_ref void* p, storage_ptr sp); - static - BOOST_JSON_DECL - value - from_init_list( - void const* p, - storage_ptr sp); - inline bool is_key_value_pair() const noexcept; diff --git a/test/basic_parser.cpp b/test/basic_parser.cpp index 82ac57f67..8533fd8ee 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("- "); @@ -1387,6 +1387,7 @@ class basic_parser_test TEST_BAD("\"\xf1\x7f\xbf\xbf----------\""); TEST_BAD("\"\xf2\x80\x7f\xbf----------\""); TEST_BAD("\"\xf3\x80\xbf\xce----------\""); + TEST_BAD("\"\xf3\x80\xbf"); // utf8 after escape TEST_GOOD("\"\\u0000 \xf3\xbf\x80\xbf\xf3\xbf\x80\xbf\""); @@ -1752,6 +1753,60 @@ 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 + testWhitespace() + { + parse_options opts; + opts.allow_comments = true; + TEST_BAD_EXT("//\n ", opts); + } + void run() { @@ -1776,6 +1831,8 @@ class basic_parser_test testNumberLiteral(); testStickyErrors(); testStdTypes(); + testManualFail(); + testWhitespace(); } }; 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 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 5b1b17501..403fe08e0 100644 --- a/test/null_resource.cpp +++ b/test/null_resource.cpp @@ -37,8 +37,8 @@ class null_resource_test #if defined(BOOST_GCC) && BOOST_GCC >= 160000 # pragma GCC diagnostic pop #endif - 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/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 diff --git a/test/serialize.cpp b/test/serialize.cpp index ff3993655..bfc8e845e 100644 --- a/test/serialize.cpp +++ b/test/serialize.cpp @@ -56,6 +56,14 @@ class serialize_test BOOST_TEST(serialize(str) == "\"123\""); BOOST_TEST(print(str) == "\"123\""); } + { + string const str(BOOST_JSON_STACK_BUFFER_SIZE, '0'); + string str_quoted = str; + str_quoted.insert(0, '"'); + str_quoted.append(1, '"'); + BOOST_TEST(serialize(str) == str_quoted); + BOOST_TEST(print(str) == str_quoted); + } } void diff --git a/test/serializer.cpp b/test/serializer.cpp index 5268b20f6..6a3b6c913 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -802,7 +802,7 @@ class serializer_test double d = 3.12; check_udt(d, "3.12e+00"); -#if defined(BOOST_HAS_INT128) && defined(__GLIBCXX_TYPE_INT_N_0) +#ifdef BOOST_HAS_INT128 boost::int128_type ii = (std::numeric_limits::max)(); ii += 1; @@ -813,7 +813,7 @@ class serializer_test ii -= 1; d = ii; check_udt( ii, serialize(value(d)) ); -#endif +#endif // BOOST_HAS_INT128 } { std::string s = "fairly long string which avoids SBO"; 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 diff --git a/test/value.cpp b/test/value.cpp index 5b11491ad..97ec3dc6e 100644 --- a/test/value.cpp +++ b/test/value.cpp @@ -2268,6 +2268,9 @@ class value_test BOOST_TEST_THROWS_WITH_LOCATION( cjvo.at("null") ); BOOST_TEST( cjvo.try_at("null").error() == error::out_of_range ); + BOOST_TEST_THROWS_WITH_LOCATION( jvo.try_at(1)->as_string() ); + BOOST_TEST_THROWS_WITH_LOCATION( cjvo.try_at(1)->as_string() ); + // array value jva{true,2,"3"}; value const& cjva = jva; @@ -2282,6 +2285,9 @@ class value_test BOOST_TEST( &elem2 == &jva.at(1) ); BOOST_TEST( &elem2 == &*jva.try_at(1) ); + BOOST_TEST_THROWS_WITH_LOCATION( jva.try_at("k1")->as_string() ); + BOOST_TEST_THROWS_WITH_LOCATION( cjva.try_at("k1")->as_string() ); + BOOST_TEST_THROWS_WITH_LOCATION( value({false,2,false}).at(4) ); BOOST_TEST_THROWS_WITH_LOCATION( value({false,2,"3"}).at(4) ); BOOST_TEST_THROWS_WITH_LOCATION( value({false,false}).at(4) );