• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   util_manip_add_value.cpp
9  * \author Andrey Semashev
10  * \date   07.11.2013
11  *
12  * \brief  This header contains tests for the \c add_value manipulator.
13  */
14 
15 #define BOOST_TEST_MODULE util_manip_add_value
16 
17 #include <iomanip>
18 #include <iostream>
19 #include <boost/move/core.hpp>
20 #include <boost/io/ios_state.hpp>
21 #include <boost/test/unit_test.hpp>
22 #include <boost/log/core.hpp>
23 #include <boost/log/sources/record_ostream.hpp>
24 #include <boost/log/attributes/attribute_set.hpp>
25 #include <boost/log/attributes/value_extraction.hpp>
26 #include <boost/log/expressions/keyword.hpp>
27 #include <boost/log/utility/manipulators/add_value.hpp>
28 #include "make_record.hpp"
29 
30 namespace logging = boost::log;
31 
32 struct my_type
33 {
34     BOOST_COPYABLE_AND_MOVABLE(my_type)
35 
36 public:
37     unsigned int value;
38 
my_typemy_type39     explicit my_type(unsigned int n = 0) : value(n) {}
my_typemy_type40     my_type(my_type const& that) : value(that.value) {}
my_typemy_type41     my_type(BOOST_RV_REF(my_type) that) : value(that.value) { that.value = 0xbaadbaad; }
~my_typemy_type42     ~my_type() { value = 0xdeaddead; }
43 
operator =my_type44     my_type& operator= (BOOST_COPY_ASSIGN_REF(my_type) that) { value = that.value; return *this; }
operator =my_type45     my_type& operator= (BOOST_RV_REF(my_type) that) { value = that.value; that.value = 0xbaadbaad; return *this; }
46 };
47 
operator ==(my_type const & left,my_type const & right)48 inline bool operator== (my_type const& left, my_type const& right)
49 {
50     return left.value == right.value;
51 }
52 
operator !=(my_type const & left,my_type const & right)53 inline bool operator!= (my_type const& left, my_type const& right)
54 {
55     return left.value != right.value;
56 }
57 
58 template< typename CharT, typename TraitsT >
operator <<(std::basic_ostream<CharT,TraitsT> & strm,my_type const & val)59 inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_type const& val)
60 {
61     if (strm.good())
62     {
63         boost::io::ios_flags_saver flags(strm);
64         boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm);
65         strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value;
66     }
67     return strm;
68 }
69 
70 struct my_pod_type
71 {
72     unsigned int value;
73 };
74 
operator ==(my_pod_type const & left,my_pod_type const & right)75 inline bool operator== (my_pod_type const& left, my_pod_type const& right)
76 {
77     return left.value == right.value;
78 }
79 
operator !=(my_pod_type const & left,my_pod_type const & right)80 inline bool operator!= (my_pod_type const& left, my_pod_type const& right)
81 {
82     return left.value != right.value;
83 }
84 
85 template< typename CharT, typename TraitsT >
operator <<(std::basic_ostream<CharT,TraitsT> & strm,my_pod_type const & val)86 inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_pod_type const& val)
87 {
88     if (strm.good())
89     {
90         boost::io::ios_flags_saver flags(strm);
91         boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm);
92         strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value;
93     }
94     return strm;
95 }
96 
BOOST_AUTO_TEST_CASE(manual_add_attr)97 BOOST_AUTO_TEST_CASE(manual_add_attr)
98 {
99     logging::record rec = make_record(logging::attribute_set());
100     BOOST_REQUIRE(!!rec);
101     logging::record_ostream strm(rec);
102 
103     my_type val(0xaaaaaaaa);
104     const my_type const_val(0xbbbbbbbb);
105     strm << logging::add_value("MyAttr1", val) << logging::add_value("MyAttr2", const_val) << logging::add_value("MyAttr3", my_type(0xcccccccc));
106 
107     // Test for MSVC bug: if the value is a scalar type, it saves a dangling reference to the add_value_manip,
108     // which results in garbage in the attribute value
109     strm << logging::add_value("MyAttr4", 100u);
110     strm << logging::add_value("MyAttr5", my_pod_type());
111 
112     strm.detach_from_record();
113 
114     BOOST_CHECK_EQUAL(rec["MyAttr1"].extract< my_type >(), val);
115     BOOST_CHECK_EQUAL(rec["MyAttr2"].extract< my_type >(), const_val);
116     BOOST_CHECK_EQUAL(rec["MyAttr3"].extract< my_type >(), my_type(0xcccccccc));
117     BOOST_CHECK_EQUAL(rec["MyAttr4"].extract< unsigned int >(), 100u);
118     BOOST_CHECK_EQUAL(rec["MyAttr5"].extract< my_pod_type >(), my_pod_type());
119 }
120 
121 BOOST_LOG_ATTRIBUTE_KEYWORD(a_my1, "MyAttr1", my_type)
122 BOOST_LOG_ATTRIBUTE_KEYWORD(a_my2, "MyAttr2", my_type)
123 BOOST_LOG_ATTRIBUTE_KEYWORD(a_my3, "MyAttr3", my_type)
124 
BOOST_AUTO_TEST_CASE(keyword_add_attr)125 BOOST_AUTO_TEST_CASE(keyword_add_attr)
126 {
127     logging::record rec = make_record(logging::attribute_set());
128     BOOST_REQUIRE(!!rec);
129     logging::record_ostream strm(rec);
130 
131     my_type val(0xaaaaaaaa);
132     const my_type const_val(0xbbbbbbbb);
133     strm << logging::add_value(a_my1, val) << logging::add_value(a_my2, const_val) << logging::add_value(a_my3, my_type(0xcccccccc));
134     strm.detach_from_record();
135 
136     BOOST_CHECK_EQUAL(rec[a_my1], val);
137     BOOST_CHECK_EQUAL(rec[a_my2], const_val);
138     BOOST_CHECK_EQUAL(rec[a_my3], my_type(0xcccccccc));
139 }
140