/* * Copyright Andrey Semashev 2007 - 2015. * 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) */ /*! * \file util_manip_add_value.cpp * \author Andrey Semashev * \date 07.11.2013 * * \brief This header contains tests for the \c add_value manipulator. */ #define BOOST_TEST_MODULE util_manip_add_value #include #include #include #include #include #include #include #include #include #include #include #include "make_record.hpp" namespace logging = boost::log; struct my_type { BOOST_COPYABLE_AND_MOVABLE(my_type) public: unsigned int value; explicit my_type(unsigned int n = 0) : value(n) {} my_type(my_type const& that) : value(that.value) {} my_type(BOOST_RV_REF(my_type) that) : value(that.value) { that.value = 0xbaadbaad; } ~my_type() { value = 0xdeaddead; } my_type& operator= (BOOST_COPY_ASSIGN_REF(my_type) that) { value = that.value; return *this; } my_type& operator= (BOOST_RV_REF(my_type) that) { value = that.value; that.value = 0xbaadbaad; return *this; } }; inline bool operator== (my_type const& left, my_type const& right) { return left.value == right.value; } inline bool operator!= (my_type const& left, my_type const& right) { return left.value != right.value; } template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_type const& val) { if (strm.good()) { boost::io::ios_flags_saver flags(strm); boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm); strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value; } return strm; } struct my_pod_type { unsigned int value; }; inline bool operator== (my_pod_type const& left, my_pod_type const& right) { return left.value == right.value; } inline bool operator!= (my_pod_type const& left, my_pod_type const& right) { return left.value != right.value; } template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_pod_type const& val) { if (strm.good()) { boost::io::ios_flags_saver flags(strm); boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm); strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value; } return strm; } BOOST_AUTO_TEST_CASE(manual_add_attr) { logging::record rec = make_record(logging::attribute_set()); BOOST_REQUIRE(!!rec); logging::record_ostream strm(rec); my_type val(0xaaaaaaaa); const my_type const_val(0xbbbbbbbb); strm << logging::add_value("MyAttr1", val) << logging::add_value("MyAttr2", const_val) << logging::add_value("MyAttr3", my_type(0xcccccccc)); // Test for MSVC bug: if the value is a scalar type, it saves a dangling reference to the add_value_manip, // which results in garbage in the attribute value strm << logging::add_value("MyAttr4", 100u); strm << logging::add_value("MyAttr5", my_pod_type()); strm.detach_from_record(); BOOST_CHECK_EQUAL(rec["MyAttr1"].extract< my_type >(), val); BOOST_CHECK_EQUAL(rec["MyAttr2"].extract< my_type >(), const_val); BOOST_CHECK_EQUAL(rec["MyAttr3"].extract< my_type >(), my_type(0xcccccccc)); BOOST_CHECK_EQUAL(rec["MyAttr4"].extract< unsigned int >(), 100u); BOOST_CHECK_EQUAL(rec["MyAttr5"].extract< my_pod_type >(), my_pod_type()); } BOOST_LOG_ATTRIBUTE_KEYWORD(a_my1, "MyAttr1", my_type) BOOST_LOG_ATTRIBUTE_KEYWORD(a_my2, "MyAttr2", my_type) BOOST_LOG_ATTRIBUTE_KEYWORD(a_my3, "MyAttr3", my_type) BOOST_AUTO_TEST_CASE(keyword_add_attr) { logging::record rec = make_record(logging::attribute_set()); BOOST_REQUIRE(!!rec); logging::record_ostream strm(rec); my_type val(0xaaaaaaaa); const my_type const_val(0xbbbbbbbb); strm << logging::add_value(a_my1, val) << logging::add_value(a_my2, const_val) << logging::add_value(a_my3, my_type(0xcccccccc)); strm.detach_from_record(); BOOST_CHECK_EQUAL(rec[a_my1], val); BOOST_CHECK_EQUAL(rec[a_my2], const_val); BOOST_CHECK_EQUAL(rec[a_my3], my_type(0xcccccccc)); }