// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2021 Peter Dimov // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // // Test that header file is self-contained. #include #include #include #include #include #include #include "test.hpp" #include "test_suite.hpp" struct X { int a; float b; std::string c; }; BOOST_DESCRIBE_STRUCT(X, (), (a, b, c)) bool operator==( X const& x1, X const& x2 ) { return x1.a == x2.a && x1.b == x2.b && x1.c == x2.c; } struct Y { std::vector v; std::map m; }; BOOST_DESCRIBE_STRUCT(Y, (), (v, m)) bool operator==( Y const& y1, Y const& y2 ) { return y1.v == y2.v && y1.m == y2.m; } BOOST_DEFINE_ENUM_CLASS(E, x, y, z) namespace boost { namespace json { class parse_into_test { public: template void testParseInto( T const& t ) { #if defined(__GNUC__) && __GNUC__ < 5 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif T t1( t ); std::string json = serialize( value_from( t1 ) ); T t2{}; error_code jec; parse_into(t2, json, jec); BOOST_TEST( !jec.failed() ) && BOOST_TEST( t1 == t2 ); T t3{}; std::error_code ec; parse_into(t3, json, ec); BOOST_TEST( !ec ) && BOOST_TEST( t1 == t3 ); T t4{}; parse_into(t4, json); BOOST_TEST( t1 == t4 ); std::istringstream is(json); T t5{}; jec = {}; parse_into(t5, is, jec); BOOST_TEST( !jec.failed() ) && BOOST_TEST( t1 == t5 ); is.clear(); is.seekg(0); T t6{}; ec = {}; parse_into(t6, is, ec); BOOST_TEST( !ec ) && BOOST_TEST( t1 == t6 ); is.clear(); is.seekg(0); T t7{}; parse_into(t7, is); BOOST_TEST( t1 == t7 ); #if defined(__GNUC__) && __GNUC__ < 5 # pragma GCC diagnostic pop #endif } template void testParseIntoErrors( error e, value const& sample ) { #if defined(__GNUC__) && __GNUC__ < 5 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif error_code ec; T t{}; std::string json = serialize(sample); parse_into(t, json, ec); BOOST_TEST( ec.failed() ); BOOST_TEST( ec.has_location() ); BOOST_TEST( ec == e ); #if defined(__GNUC__) && __GNUC__ < 5 # pragma GCC diagnostic pop #endif } void testNull() { testParseInto( nullptr ); testParseIntoErrors< std::nullptr_t >( error::not_null, 1 ); } void testBoolean() { testParseInto( false ); testParseInto( true ); testParseIntoErrors< bool >( error::not_bool, 1 ); } void testIntegral() { testParseInto( 'A' ); // ? testParseInto( -127 ); testParseInto( 255 ); testParseInto( -32767 ); testParseInto( 65535 ); testParseInto( -32767 ); testParseInto( 65535 ); testParseInto( LONG_MIN ); testParseInto( ULONG_MAX ); testParseInto( LLONG_MIN ); testParseInto( ULLONG_MAX ); testParseIntoErrors< int >( error::not_integer, "1" ); testParseIntoErrors< int >( error::not_integer, true ); testParseIntoErrors< int >( error::not_exact, LLONG_MIN ); testParseIntoErrors< int >( error::not_exact, ULONG_MAX ); } void testFloatingPoint() { testParseInto( 0.25f ); testParseInto( 1.125 ); // value_from doesn't support long double // testParseInto( 2.25L ); testParseIntoErrors< double >( error::not_double, "1" ); } void testString() { testParseInto( "" ); testParseInto( "12345" ); testParseIntoErrors< string >( error::not_string, 1 ); } void testSequence() { testParseInto>( { nullptr, nullptr } ); testParseInto< std::vector >( {} ); testParseInto< std::vector >( { true, false } ); testParseInto< std::vector >( {} ); testParseInto< std::vector >( { 1, 2, 3 } ); testParseInto< std::vector >( {} ); testParseInto< std::vector >( { 1.02f, 2.11f, 3.14f } ); testParseInto< std::vector >( {} ); testParseInto< std::vector >( { "one", "two", "three" } ); testParseInto< std::vector> >( {} ); testParseInto< std::vector> >( { {}, { 1 }, { 2, 3 }, { 4, 5, 6 } } ); // clang <= 5 doesn't like when std::array is created from init-list std::array arr; arr.fill(17); testParseInto< std::array >( arr ); testParseIntoErrors< std::vector >( error::not_array, 1 ); testParseIntoErrors< std::vector >( error::not_array, "abcd" ); testParseIntoErrors< std::vector> >( error::not_array, { 1, 2, 3} ); } void testMap() { testParseInto< std::map >( {} ); testParseInto< std::map >( { { "one", 1 }, { "two", 2 } } ); testParseInto< std::map >( {} ); testParseInto< std::map >( { { "one", 1 }, { "two", 2 } } ); testParseInto< std::map> >( {} ); testParseInto< std::map> >( { { "one", { 1 } }, { "two", { 2, 3 } } } ); testParseInto< std::map> >( {} ); testParseInto< std::map> >( { { "one", {} }, { "two", { { "1", 1 }, { "2", 2 } } } } ); testParseIntoErrors< std::map >( error::not_object, { "1", 1, "2", 2} ); testParseIntoErrors< std::map> >( error::not_object, { {"1", {}}, {"2", {"3", 4}} } ); } void testTuple() { testParseInto>( {} ); testParseInto>( { 1, 3.14f } ); testParseInto>( {} ); testParseInto>( std::make_tuple(1, 3.14f, "hello") ); testParseInto>>( {} ); testParseInto>>( { { 1, 2 }, { 3, 4 } } ); testParseInto>>>( {} ); testParseInto>>>( { { { 1, 2 }, { 3, 4 } } } ); testParseInto>>>( { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } } ); testParseInto>>>( {} ); testParseInto>>>( { { "one", {} } } ); testParseInto>>>( { { "one", { { 1, 2 }, { 3, 4 } } } } ); testParseInto, std::map>>>( {} ); testParseInto, std::map>>>( { { 1, 2, 3 }, { { "one", { 7, true } } } } ); testParseIntoErrors< std::pair >( error::not_array, 1 ); // these two should be errors too // testParseIntoErrors< std::pair >( // error::size_mismatch, {1, 2, 3} ); // testParseIntoErrors< std::tuple >( // error::size_mismatch, {1, 2} ); } void testStruct() { #if defined(BOOST_DESCRIBE_CXX14) testParseInto( {} ); testParseInto( { 1, 3.14f, "hello" } ); testParseInto( {} ); testParseInto( { { { 1, 1.0f, "one" }, { 2, 2.0f, "two" } }, { { "one", { 1, 1.1f, "1" } }, { "two", { 2, 2.2f, "2" } } } } ); testParseIntoErrors( error::not_object, 1 ); testParseIntoErrors( error::unknown_name, { {"a", 1}, {"b", 3.14f}, {"c", "hello"}, {"d", 0} } ); // this two should be an error too // testParseIntoErrors( error::size_mismatch, { {"a", 1} } ); #endif } void testEnum() { #ifdef BOOST_DESCRIBE_CXX14 testParseInto( E::x ); testParseInto( E::y ); testParseInto( E::z ); testParseIntoErrors< E >( error::not_string, (int)(E::y) ); #endif // BOOST_DESCRIBE_CXX14 } template< template class Variant, class Monostate > void testVariant() { testParseInto< Variant >( 1 ); testParseInto< Variant >( 1 ); testParseInto< Variant >( "qwerty" ); testParseInto< Variant >( {} ); testParseInto< Variant >( 1 ); testParseInto< Variant >( "qwerty" ); testParseInto< Variant< std::vector > >( std::vector{1, 2, 3, 4, 5} ); testParseInto< Variant< Monostate, std::vector > >( std::vector{1, 2, 3, 4, 5} ); testParseInto< std::vector< Variant > >( {1, 2, 3, "four", 5, "six", "seven", 8}); using V = Variant< std::vector< int >, std::tuple< int, std::string, std::map >, std::tuple< int, std::string, std::map > >; testParseInto< V >( std::make_tuple( 5, "five", std::map{ {"one", 1}, {"pi", 3.14} })); testParseIntoErrors< Variant >( error::exhausted_variants, "a" ); testParseIntoErrors< Variant >( error::exhausted_variants, "a" ); testParseIntoErrors< Variant >( error::exhausted_variants, "a" ); } void testOptional() { #ifndef BOOST_NO_CXX17_HDR_OPTIONAL testParseInto< std::optional >( std::nullopt ); testParseInto< std::optional >( 1 ); testParseInto< std::optional> >( std::nullopt ); testParseInto< std::optional> >( std::vector{} ); testParseInto< std::optional> >( std::vector{nullptr, nullptr} ); testParseInto< std::optional> >( std::vector{"1", "2", "3"} ); testParseInto< std::vector< std::optional > >( {1, 2, 3, std::nullopt, 5, std::nullopt, std::nullopt, 8}); #endif } void run() { testNull(); testBoolean(); testIntegral(); testFloatingPoint(); testString(); testSequence(); testMap(); testTuple(); testStruct(); testEnum(); testOptional(); testVariant(); #ifndef BOOST_NO_CXX17_HDR_VARIANT testVariant(); #endif } }; TEST_SUITE(parse_into_test, "boost.json.parse_into"); } // namespace boost } // namespace json