#include #include #include #include #include #include #include namespace fc { namespace test { struct item; inline bool operator == ( const item& a, const item& b ); inline bool operator < ( const item& a, const item& b ); struct item_wrapper { item_wrapper() {} item_wrapper(item&& it) { v.reserve(1); v.insert( it ); } boost::container::flat_set v; }; inline bool operator == ( const item_wrapper& a, const item_wrapper& b ) { return ( std::tie( a.v ) == std::tie( b.v ) ); } inline bool operator < ( const item_wrapper& a, const item_wrapper& b ) { return ( std::tie( a.v ) < std::tie( b.v ) ); } struct item { item(int32_t lvl = 0) : level(lvl) {} item(item_wrapper&& wp, int32_t lvl = 0) : level(lvl), w(wp) {} int32_t level; item_wrapper w; }; inline bool operator == ( const item& a, const item& b ) { return ( std::tie( a.level, a.w ) == std::tie( b.level, b.w ) ); } inline bool operator < ( const item& a, const item& b ) { return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); } } } // namespace fc::test FC_REFLECT( fc::test::item_wrapper, (v) ); FC_REFLECT( fc::test::item, (level)(w) ); BOOST_AUTO_TEST_SUITE(fc_variant_and_log) BOOST_AUTO_TEST_CASE( types_edge_cases_test ) { using namespace fc::test; class sv : public fc::static_variant<> { public: BOOST_ATTRIBUTE_UNUSED typedef fc::static_variant<>::tag_type tag_type; }; BOOST_TEST_MESSAGE( "========== Test empty static_variant ==========" ); BOOST_CHECK_THROW( fc::static_variant<>(), fc::assert_exception ); BOOST_TEST_MESSAGE( "========== Test static_variant with tag_type ==========" ); sv::tag_type init_value = 2; fc::static_variant< sv::tag_type, std::string, fc::variant > variant_with_tagtype(init_value); BOOST_CHECK_EQUAL( variant_with_tagtype.count(), 3 ); BOOST_CHECK_EQUAL( variant_with_tagtype.which(), 0 ); sv::tag_type current_value = variant_with_tagtype.get(); BOOST_CHECK_EQUAL( current_value, init_value ); BOOST_CHECK( variant_with_tagtype.get() == init_value ); for (sv::tag_type i = variant_with_tagtype.count(); i-->0;) { variant_with_tagtype.set_which(i); BOOST_CHECK_EQUAL(variant_with_tagtype.which(), i); } BOOST_TEST_MESSAGE( "========== Test static_variant with static_variant ==========" ); using sv_double = fc::static_variant; using sv_float = fc::static_variant; fc::static_variant< sv_float, std::string, sv_double > variant; sv_float variant_float = 1.5f; variant = variant_float; BOOST_CHECK_EQUAL( variant.which(), 0 ); BOOST_CHECK_EQUAL( variant.get().get(), 1.5f ); sv_double variant_double = 1.0; variant = variant_double; BOOST_CHECK_EQUAL( variant.which() , 2); BOOST_CHECK_EQUAL( variant.get().get(), 1.0 ); } BOOST_AUTO_TEST_CASE( nested_objects_test ) { try { ilog( "Suppressing logging (but not disabled)" ); fc::logging_config cfg; fc::logger_config dlc; dlc.name = "default"; dlc.level = fc::log_level::debug; dlc.appenders.push_back("stderr"); cfg.loggers.push_back( dlc ); fc::configure_logging( cfg ); auto create_nested_object = []( uint32_t level ) { ilog( "Creating nested object with ${lv} level(s)", ("lv",level) ); fc::test::item nested; for( uint32_t i = 1; i <= level; i++ ) { if( i % 10 == 0 ) ilog( "Creating level ${lv}", ("lv",i) ); fc::test::item_wrapper wp( std::move(nested) ); nested = fc::test::item( std::move(wp), i ); } return nested; }; for (int nested_loops = 0; nested_loops <= 100; ++nested_loops ) { int nested_levels = nested_loops * 3 + 2; auto nested = create_nested_object( nested_loops ); fc::variant v; BOOST_TEST_MESSAGE( "========== About to nested object convert to variant. ==========" ); BOOST_CHECK_THROW( to_variant( nested, v, nested_levels ), fc::assert_exception ); try{ try { try { try { to_variant( nested, v, nested_levels ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (nested) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (nested) ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (nested) ); // CAPTURE_AND_LOG should never throw again to_variant( nested, v, nested_levels + 1 ); BOOST_TEST_MESSAGE( "========== About to convert nested object from variant. ==========" ); fc::test::item unpacked; BOOST_CHECK_THROW( from_variant( v, unpacked, nested_levels ), fc::assert_exception ); try{ try { try { try { from_variant( v, unpacked, nested_levels ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (v) ); // CAPTURE_AND_LOG should never throw again from_variant( v, unpacked, nested_levels + 1 ); BOOST_CHECK( unpacked == nested ); // both log and dump should never throw BOOST_TEST_MESSAGE( "========== About to log obj. ==========" ); ilog( "The obj is ${a}, variant is ${v}", ("a",nested)("v",v) ); BOOST_TEST_MESSAGE( "========== About to dump obj. ==========" ); idump( (nested)(v) ); fc::static_variant sv( nested ), sv1; BOOST_TEST_MESSAGE( "========== About to convert static_variant to variant. ==========" ); BOOST_CHECK_THROW( to_variant( sv, v, nested_levels + 1 ), fc::assert_exception ); try{ try { try { try { to_variant( sv, v, nested_levels + 1 ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (sv) ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (sv) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (sv) ); // CAPTURE_AND_LOG should never throw again to_variant( sv, v, nested_levels + 2 ); BOOST_TEST_MESSAGE( "========== About to convert static_variant from variant. ==========" ); BOOST_CHECK_THROW( from_variant( v, sv1, nested_levels + 1 ), fc::assert_exception ); try{ try { try { try { from_variant( v, sv1, nested_levels + 1 ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (v) ); // CAPTURE_AND_LOG should never throw again from_variant( v, sv1, nested_levels + 2 ); auto sv_equal = [](const fc::static_variant& v1, const fc::static_variant& v2) { return v1.get() == v2.get(); }; BOOST_CHECK( sv_equal(sv, sv1) ); // both log and dump should never throw BOOST_TEST_MESSAGE( "========== About to log static_variant. ==========" ); wlog( "The static_variant is ${a}, variant is $(v)", ("a",sv)("v",v) ); BOOST_TEST_MESSAGE( "========== About to dump static_variant. ==========" ); wdump( (sv)(v) ); std::vector> vec(300), vec1; for( int i = 0; i < 300; i++ ) vec.push_back(sv); BOOST_TEST_MESSAGE( "========== About to convert vector to variant. ==========" ); BOOST_CHECK_THROW( to_variant( vec, v, nested_levels + 2 ), fc::assert_exception ); try{ try { try { try { to_variant( vec, v, nested_levels + 2 ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (vec) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (vec) ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (vec) ); // CAPTURE_AND_LOG should never throw again to_variant( vec, v, nested_levels + 3 ); BOOST_TEST_MESSAGE( "========== About to convert vector from variant. ==========" ); BOOST_CHECK_THROW( from_variant( v, vec1, nested_levels + 2 ), fc::assert_exception ); try{ try { try { try { from_variant( v, vec1, nested_levels + 2 ); BOOST_FAIL( "Expected exception." ); } FC_LOG_AND_RETHROW( ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_LOG_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_RETHROW( (v) ); BOOST_FAIL( "Expected exception." ); } FC_CAPTURE_AND_LOG ( (v) ); // CAPTURE_AND_LOG should never throw again from_variant( v, vec1, nested_levels + 3 ); BOOST_CHECK( std::equal(vec.begin(), vec.end(), vec1.begin(), sv_equal) ); // both log and dump should never throw BOOST_TEST_MESSAGE( "========== About to log vector. ==========" ); elog( "The vector is ${a}, variant is ${v}", ("a",vec)("v",v) ); BOOST_TEST_MESSAGE( "========== About to dump vector. ==========" ); edump( (vec)(v) ); } fc::configure_logging( fc::logging_config::default_config() ); ilog( "End suppressing logging" ); } FC_CAPTURE_LOG_AND_RETHROW ( (0) ) } BOOST_AUTO_TEST_SUITE_END()