1 /*
2 * Copyright Andrey Semashev 2016.
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 form_max_size_decor.cpp
9 * \author Andrey Semashev
10 * \date 09.08.2016
11 *
12 * \brief This header contains tests for the \c max_size_decor formatter.
13 */
14
15 #define BOOST_TEST_MODULE form_max_size_decor
16
17 #include <string>
18 #include <locale>
19 #include <boost/test/unit_test.hpp>
20 #include <boost/log/attributes/constant.hpp>
21 #include <boost/log/attributes/attribute_set.hpp>
22 #include <boost/log/utility/type_dispatch/standard_types.hpp>
23 #include <boost/log/utility/formatting_ostream.hpp>
24 #include <boost/log/expressions/attr.hpp>
25 #include <boost/log/expressions/formatter.hpp>
26 #include <boost/log/expressions/formatters/max_size_decorator.hpp>
27 #include <boost/log/expressions/formatters/stream.hpp>
28 #include <boost/log/core/record.hpp>
29 #include <boost/phoenix/operator.hpp>
30 #include "char_definitions.hpp"
31 #include "make_record.hpp"
32
33 #define BOOST_UTF8_DECL
34 #define BOOST_UTF8_BEGIN_NAMESPACE namespace {
35 #define BOOST_UTF8_END_NAMESPACE }
36
37 #include <boost/detail/utf8_codecvt_facet.hpp>
38 #include <boost/detail/utf8_codecvt_facet.ipp>
39
40 namespace logging = boost::log;
41 namespace attrs = logging::attributes;
42 namespace expr = logging::expressions;
43
44 namespace {
45
46 template< typename >
47 struct test_strings;
48
49 #ifdef BOOST_LOG_USE_CHAR
50 template< >
51 struct test_strings< char > : public test_data< char >
52 {
printable_chars__anonecc869600111::test_strings53 static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
overflow_marker__anonecc869600111::test_strings54 static const char* overflow_marker() { return ">>>"; }
55 };
56 #endif
57
58 #ifdef BOOST_LOG_USE_WCHAR_T
59 template< >
60 struct test_strings< wchar_t > : public test_data< wchar_t >
61 {
printable_chars__anonecc869600111::test_strings62 static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
overflow_marker__anonecc869600111::test_strings63 static const wchar_t* overflow_marker() { return L">>>"; }
64 };
65 #endif
66
67 } // namespace
68
BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting,CharT,char_types)69 BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
70 {
71 typedef logging::record_view record_view;
72 typedef logging::attribute_set attr_set;
73 typedef std::basic_string< CharT > string;
74 typedef logging::basic_formatting_ostream< CharT > osstream;
75 typedef logging::basic_formatter< CharT > formatter;
76 typedef test_strings< CharT > data;
77
78 attrs::constant< string > attr1(data::printable_chars());
79
80 attr_set set1;
81 set1[data::attr1()] = attr1;
82
83 record_view rec = make_record_view(set1);
84
85 // Test output truncation
86 {
87 string str1, str2;
88 osstream strm1(str1), strm2(str2);
89 formatter f = expr::stream << expr::max_size_decor< CharT >(10)[ expr::stream << expr::attr< string >(data::attr1()) << data::some_test_string() << 1234 << data::abc() ];
90 f(rec, strm1);
91 strm2 << string(data::printable_chars(), 10);
92 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
93 }
94
95 // Test output truncation with a marker
96 {
97 string str1, str2;
98 osstream strm1(str1), strm2(str2);
99 formatter f = expr::stream << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) << data::some_test_string() << 1234 << data::abc() ];
100 f(rec, strm1);
101 strm2 << string(data::printable_chars(), 7) << data::overflow_marker();
102 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
103 }
104
105 // Test nested decorators, when the outer decorator enforces the limit that includes the inner decorator
106 {
107 string str1, str2;
108 osstream strm1(str1), strm2(str2);
109 formatter f = expr::stream << expr::max_size_decor(35, data::overflow_marker())[
110 expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
111 ];
112 f(rec, strm1);
113 strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 7) << data::overflow_marker() << string(data::abcdefg0123456789(), 5) << data::overflow_marker();
114 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
115 }
116
117 // Test nested decorators, when the outer decorator enforces the limit that also limits the inner decorator
118 {
119 string str1, str2;
120 osstream strm1(str1), strm2(str2);
121 formatter f = expr::stream << expr::max_size_decor(25, data::overflow_marker())[
122 expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
123 ];
124 f(rec, strm1);
125 strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 5) << data::overflow_marker();
126 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
127 }
128 }
129
130 namespace {
131
132 const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
133
134 } // namespace
135
BOOST_AUTO_TEST_CASE(character_boundary_maintenance)136 BOOST_AUTO_TEST_CASE(character_boundary_maintenance)
137 {
138 typedef logging::record_view record_view;
139 typedef logging::attribute_set attr_set;
140 typedef std::basic_string< char > string;
141 typedef logging::basic_formatting_ostream< char > osstream;
142 typedef logging::basic_formatter< char > formatter;
143 typedef test_strings< char > data;
144
145 std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
146
147 attrs::constant< string > attr1(narrow_chars);
148
149 attr_set set1;
150 set1[data::attr1()] = attr1;
151
152 record_view rec = make_record_view(set1);
153
154 // Test that output truncation does not happen in the middle of a multibyte character
155 {
156 string str1, str2;
157 osstream strm1(str1), strm2(str2);
158 strm1.imbue(loc);
159 strm2.imbue(loc);
160 formatter f = expr::stream << expr::max_size_decor< char >(7)[ expr::stream << expr::attr< string >(data::attr1()) ];
161 f(rec, strm1);
162 strm2 << string(narrow_chars, 6);
163 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
164 }
165
166 // Test output truncation with a marker, when the marker length would have caused truncation in the middle of a multibyte character
167 {
168 string str1, str2;
169 osstream strm1(str1), strm2(str2);
170 strm1.imbue(loc);
171 strm2.imbue(loc);
172 formatter f = expr::stream << expr::max_size_decor(6, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ];
173 f(rec, strm1);
174 strm2 << string(narrow_chars, 2) << data::overflow_marker();
175 BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
176 }
177 }
178