diff --git a/.drone.star b/.drone.star index ce5526b8f..6c997a42b 100644 --- a/.drone.star +++ b/.drone.star @@ -98,7 +98,6 @@ def main(ctx): 'LCOV_BRANCH_COVERAGE': '0', 'B2_CXXSTD': '23', 'B2_VARIANT': 'debug', - 'B2_DEFINES': 'BOOST_JSON_EXPENSIVE_TESTS', 'CODECOV_TOKEN': {'from_secret': 'codecov_token'}, }, }, @@ -122,9 +121,15 @@ def main(ctx): }, { 'match': {'compiler': 'clang =latest', 'os': 'linux'}, 'special': 'valgrind', + 'environment': { + 'B2_DEFINES': 'BOOST_JSON_NO_LONG_TESTS', + }, }, { 'match': {'compiler': 'gcc =latest', 'os': 'linux'}, 'special': 'valgrind', + 'environment': { + 'B2_DEFINES': 'BOOST_JSON_NO_LONG_TESTS', + }, }, ], ) + [ 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/impl/serialize.ipp b/include/boost/json/impl/serialize.ipp index 66747e7df..92451fa11 100644 --- a/include/boost/json/impl/serialize.ipp +++ b/include/boost/json/impl/serialize.ipp @@ -80,9 +80,7 @@ serialize_impl( s.max_size() / 2; for(;;) { - sv = sr.read( - &s[0] + len, - s.size() - len); + sv = sr.read(&s[0] + len, s.size() - len); len += sv.size(); if(sr.done()) break; diff --git a/include/boost/json/impl/serializer.hpp b/include/boost/json/impl/serializer.hpp index 0a7255d06..15927b7e6 100644 --- a/include/boost/json/impl/serializer.hpp +++ b/include/boost/json/impl/serializer.hpp @@ -73,7 +73,7 @@ BOOST_FORCEINLINE bool write_impl(bool_conversion_tag, writer& w, stream& ss) { - BOOST_ASSERT( w.p_ ); + BOOST_ASSERT( w.p_ ); // LCOV_EXCL_LINE auto const t = *reinterpret_cast(w.p_); #if defined(_MSC_VER) @@ -193,7 +193,7 @@ write_impl(string_like_conversion_tag, writer& w, stream& ss0) # pragma warning( pop ) #endif { - string_view const sv = *reinterpret_cast(w.p_); + string_view const sv = *reinterpret_cast(w.p_); // LCOV_EXCL_LINE w.cs0_ = { sv.data(), sv.size() }; return write_string(w, ss0); } 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_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 7b4528b5c..5b98abb75 100644 --- a/test/basic_parser.cpp +++ b/test/basic_parser.cpp @@ -659,8 +659,8 @@ class basic_parser_test good("1000000000000000000000000.000000000001"); good("1000000000000000000000000.0e1 "); good("1000000000000000000000000.0 "); - good("1000000000.1000000000 "); + good("100000000000000000000e+2147483647"); bad(""); bad("- "); @@ -1453,6 +1453,7 @@ class basic_parser_test bad("\"\xf1\x7f\xbf\xbf----------\""); bad("\"\xf2\x80\x7f\xbf----------\""); bad("\"\xf3\x80\xbf\xce----------\""); + bad("\"\xf3\x80\xbf"); // utf8 after escape good("\"\\u0000 \xf3\xbf\x80\xbf\xf3\xbf\x80\xbf\""); @@ -1821,6 +1822,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; + bad("//\n ", opts); + } + void run() { @@ -1845,6 +1900,8 @@ class basic_parser_test testNumberLiteral(); testStickyErrors(); testStdTypes(); + testManualFail(); + testWhitespace(); } }; diff --git a/test/limits.cpp b/test/limits.cpp index df836cc3b..73156b100 100644 --- a/test/limits.cpp +++ b/test/limits.cpp @@ -192,19 +192,12 @@ class limits_test (s.insert(0, s.subview(0, 10))) ); } - #if 0 { - // VFALCO tsan doesn't like this + // capacity overflow string s; - try - { - s.resize(s.max_size() - 1); - } - catch(std::exception const&) - { - } + s.reserve(s.max_size() - 1); + s.reserve(s.max_size()); } - #endif } // string in parser @@ -220,6 +213,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; 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 f66d58035..69bd104b8 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -275,6 +275,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..0ed4cafa1 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 * 2, '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..5b44e6464 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -802,7 +802,8 @@ class serializer_test double d = 3.12; check_udt(d, "3.12e+00"); -#if defined(BOOST_HAS_INT128) && defined(__GLIBCXX_TYPE_INT_N_0) +#if defined(BOOST_HAS_INT128) \ + && defined(BOOST_GCC) && BOOST_GCC_VERSION >= 160000 boost::int128_type ii = (std::numeric_limits::max)(); ii += 1; 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/stream_parser.cpp b/test/stream_parser.cpp index b2fe17380..8655e77ab 100644 --- a/test/stream_parser.cpp +++ b/test/stream_parser.cpp @@ -1296,79 +1296,87 @@ R"xx({ void testLongNumberOverlfow() { -#ifdef BOOST_JSON_EXPENSIVE_TESTS - std::array zeroes; +#ifndef BOOST_JSON_NO_LONG_TESTS + std::array zeroes; zeroes.fill('0'); stream_parser p; { - p.write("1", 1); + // number with too many digits before decimal point + p.write("1111111111111111111", 19); std::size_t count = 0; - while( static_cast( INT_MAX - zeroes.size() ) > count ) + std::size_t const n + = static_cast(INT_MAX) - zeroes.size(); + while(n > count) count += p.write( zeroes.data(), zeroes.size() ); + p.write(zeroes.data(), static_cast(INT_MAX) - count); system::error_code ec; - p.write(zeroes.data(), zeroes.size(), ec); - BOOST_TEST( ec == error::exponent_overflow ); + p.write("1", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); } p.reset(); { + // number with too many digits after decimal point p.write("0.", 2); std::size_t count = 0; - while( static_cast( INT_MAX - zeroes.size() ) > count ) + std::size_t const n + = static_cast(INT_MAX) - zeroes.size(); + while(n > count) count += p.write( zeroes.data(), zeroes.size() ); + p.write(zeroes.data(), static_cast(INT_MAX) - count); system::error_code ec; - p.write(zeroes.data(), zeroes.size(), ec); - BOOST_TEST( ec == error::exponent_overflow ); + p.write_some("0", 1, ec); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); } p.reset(); { + // number with non-zero mantissa, many digits after decimal point, + // and overflowing negative exponent p.write("0.", 2); int count = INT_MIN; - while( static_cast( count + zeroes.size() ) < 0 ) + while( static_cast(count + zeroes.size()) < 0 ) count += static_cast( p.write( zeroes.data(), zeroes.size() )); - p.write(zeroes.data(), -2 - count); - p.write("1e", 2); - // at this point we've filled bias to the brim - std::string const int_min = std::to_string(INT_MIN); - p.write( int_min.data(), int_min.size() ); + p.write("1e-2147483647", 13); + // 0.((-INT_MIN) - 2 zeroes)1e-2147483647 system::error_code ec; p.finish(ec); - BOOST_TEST( ec == error::exponent_overflow ); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); } p.reset(); { - std::string const uint64_max - = std::to_string(18446744073709551615U); - p.write( uint64_max.data(), uint64_max.size() ); + // number with non-zero mantissa, many digits before decimal point, + // and overflowing positive exponent + p.write("1111111111111111111", 19); - std::size_t count = INT_MAX; + std::size_t count = INT_MAX - (308 - 19); while( static_cast( count - zeroes.size() ) > 0 ) count -= p.write( zeroes.data(), zeroes.size() ); + p.write(zeroes.data(), count); - p.write(zeroes.data(), count - 1); - // at this point we've filled bias to the brim - - p.write("e", 1); - std::string const int_max = std::to_string(INT_MAX); - p.write( int_max.data(), int_max.size() ); + p.write("1e+2147483647", 13); + // 1(INT_MAX - 289 zeroes)1e+2147483647 system::error_code ec; p.finish(ec); - BOOST_TEST( ec == error::exponent_overflow ); + BOOST_TEST(ec == error::exponent_overflow); + BOOST_TEST(ec.has_location()); } -#endif +#endif // BOOST_JSON_NO_LONG_TESTS } //------------------------------------------------------ diff --git a/test/string.cpp b/test/string.cpp index 35a5e23b2..ed88c3e8e 100644 --- a/test/string.cpp +++ b/test/string.cpp @@ -1395,6 +1395,14 @@ class string_test BOOST_TEST(s.size() == n); BOOST_TEST(s.capacity() == sbo_capacity); BOOST_TEST(s == string_view(copy.data(), n)); + + s.resize(sbo_capacity + 1); + cap = s.capacity(); + s.resize(cap); + s.shrink_to_fit(); + BOOST_TEST(s.capacity() == cap); + s.shrink_to_fit(); + BOOST_TEST(s.capacity() == cap); }); } 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) );