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 filt_attr.cpp
9 * \author Andrey Semashev
10 * \date 31.01.2009
11 *
12 * \brief This header contains tests for the \c attr filter.
13 */
14
15 #define BOOST_TEST_MODULE filt_attr
16
17 #include <memory>
18 #include <string>
19 #include <algorithm>
20 #include <boost/regex.hpp>
21 #include <boost/mpl/vector.hpp>
22 #include <boost/phoenix/bind.hpp>
23 #include <boost/test/unit_test.hpp>
24 #include <boost/log/attributes/constant.hpp>
25 #include <boost/log/attributes/attribute_set.hpp>
26 #include <boost/log/attributes/attribute_value_set.hpp>
27 #include <boost/log/utility/type_dispatch/standard_types.hpp>
28 #include <boost/log/support/regex.hpp>
29 #include <boost/log/expressions.hpp>
30 #include "char_definitions.hpp"
31
32 namespace phoenix = boost::phoenix;
33
34 namespace logging = boost::log;
35 namespace attrs = logging::attributes;
36 namespace expr = logging::expressions;
37
38 // The test checks that general conditions work
BOOST_AUTO_TEST_CASE(general_conditions)39 BOOST_AUTO_TEST_CASE(general_conditions)
40 {
41 typedef logging::attribute_set attr_set;
42 typedef logging::attribute_value_set attr_values;
43 typedef logging::filter filter;
44 typedef test_data< char > data;
45
46 attrs::constant< int > attr1(10);
47 attrs::constant< double > attr2(5.5);
48 attrs::constant< std::string > attr3("Hello, world!");
49
50 attr_set set1, set2, set3;
51 set1[data::attr1()] = attr1;
52 set1[data::attr2()] = attr2;
53 set1[data::attr3()] = attr3;
54
55 attr_values values1(set1, set2, set3);
56 values1.freeze();
57
58 filter f = expr::attr< int >(data::attr1()) == 10;
59 BOOST_CHECK(f(values1));
60
61 f = expr::attr< int >(data::attr1()) < 0;
62 BOOST_CHECK(!f(values1));
63
64 f = expr::attr< float >(data::attr1()).or_throw() > 0;
65 BOOST_CHECK_THROW(f(values1), logging::runtime_error);
66 f = expr::attr< float >(data::attr1()) > 0;
67 BOOST_CHECK(!f(values1));
68
69 f = expr::attr< int >(data::attr4()).or_throw() >= 1;
70 BOOST_CHECK_THROW(f(values1), logging::runtime_error);
71 f = expr::attr< int >(data::attr4()) >= 1;
72 BOOST_CHECK(!f(values1));
73
74 f = expr::attr< int >(data::attr4()) < 1;
75 BOOST_CHECK(!f(values1));
76
77 f = expr::attr< logging::numeric_types >(data::attr2()) > 5;
78 BOOST_CHECK(f(values1));
79
80 f = expr::attr< std::string >(data::attr3()) == "Hello, world!";
81 BOOST_CHECK(f(values1));
82
83 f = expr::attr< std::string >(data::attr3()) > "AAA";
84 BOOST_CHECK(f(values1));
85 }
86
87 // The test checks that is_in_range condition works
BOOST_AUTO_TEST_CASE(in_range_check)88 BOOST_AUTO_TEST_CASE(in_range_check)
89 {
90 typedef logging::attribute_set attr_set;
91 typedef logging::attribute_value_set attr_values;
92 typedef logging::filter filter;
93 typedef test_data< char > data;
94
95 attrs::constant< int > attr1(10);
96 attrs::constant< double > attr2(5.5);
97 attrs::constant< std::string > attr3("Hello, world!");
98
99 attr_set set1, set2, set3;
100 set1[data::attr1()] = attr1;
101 set1[data::attr2()] = attr2;
102 set1[data::attr3()] = attr3;
103
104 attr_values values1(set1, set2, set3);
105 values1.freeze();
106
107 filter f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 20);
108 BOOST_CHECK(f(values1));
109
110 f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 10);
111 BOOST_CHECK(!f(values1));
112
113 f = expr::is_in_range(expr::attr< int >(data::attr1()), 10, 20);
114 BOOST_CHECK(f(values1));
115
116 f = expr::is_in_range(expr::attr< logging::numeric_types >(data::attr2()), 5, 6);
117 BOOST_CHECK(f(values1));
118
119 f = expr::is_in_range(expr::attr< std::string >(data::attr3()), "AAA", "zzz");
120 BOOST_CHECK(f(values1));
121
122 // Check that strings are saved into the filter by value
123 char buf1[128];
124 char buf2[128];
125 std::strcpy(buf1, "AAA");
126 std::strcpy(buf2, "zzz");
127 f = expr::is_in_range(expr::attr< std::string >(data::attr3()), buf1, buf2);
128 std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
129 std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
130 BOOST_CHECK(f(values1));
131
132 std::strcpy(buf1, "AAA");
133 std::strcpy(buf2, "zzz");
134 f = expr::is_in_range(expr::attr< std::string >(data::attr3()),
135 static_cast< const char* >(buf1), static_cast< const char* >(buf2));
136 std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
137 std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
138 BOOST_CHECK(f(values1));
139 }
140
141 namespace {
142
143 struct predicate
144 {
145 typedef bool result_type;
146
predicate__anonc546ca0f0111::predicate147 explicit predicate(unsigned int& present_counter, bool& result) :
148 m_PresentCounter(present_counter),
149 m_Result(result)
150 {
151 }
152
153 template< typename T, typename TagT >
operator ()__anonc546ca0f0111::predicate154 result_type operator() (logging::value_ref< T, TagT > const& val) const
155 {
156 m_PresentCounter += !val.empty();
157 return m_Result;
158 }
159
160 private:
161 unsigned int& m_PresentCounter;
162 bool& m_Result;
163 };
164
165 } // namespace
166
167 // The test checks that phoenix::bind interaction works
BOOST_AUTO_TEST_CASE(bind_support_check)168 BOOST_AUTO_TEST_CASE(bind_support_check)
169 {
170 typedef logging::attribute_set attr_set;
171 typedef logging::attribute_value_set attr_values;
172 typedef logging::filter filter;
173 typedef test_data< char > data;
174
175 attrs::constant< int > attr1(10);
176 attrs::constant< double > attr2(5.5);
177 attrs::constant< std::string > attr3("Hello, world!");
178
179 attr_set set1, set2, set3;
180 set1[data::attr1()] = attr1;
181 set1[data::attr2()] = attr2;
182 set1[data::attr3()] = attr3;
183
184 attr_values values1(set1, set2, set3);
185 values1.freeze();
186
187 unsigned int present_counter = 0;
188 bool predicate_result = false;
189
190 filter f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr1()));
191 BOOST_CHECK_EQUAL(f(values1), predicate_result);
192 BOOST_CHECK_EQUAL(present_counter, 1U);
193
194 predicate_result = true;
195 BOOST_CHECK_EQUAL(f(values1), predicate_result);
196 BOOST_CHECK_EQUAL(present_counter, 2U);
197
198 f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< logging::numeric_types >(data::attr2()));
199 BOOST_CHECK_EQUAL(f(values1), predicate_result);
200 BOOST_CHECK_EQUAL(present_counter, 3U);
201
202 f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()).or_throw());
203 BOOST_CHECK_THROW(f(values1), logging::runtime_error);
204 f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()));
205 BOOST_CHECK_EQUAL(f(values1), true);
206 BOOST_CHECK_EQUAL(present_counter, 3U);
207
208 f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()).or_throw());
209 BOOST_CHECK_THROW(f(values1), logging::runtime_error);
210 f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()));
211 BOOST_CHECK_EQUAL(f(values1), true);
212 BOOST_CHECK_EQUAL(present_counter, 3U);
213 }
214
215 // The test checks that begins_with condition works
BOOST_AUTO_TEST_CASE(begins_with_check)216 BOOST_AUTO_TEST_CASE(begins_with_check)
217 {
218 typedef logging::attribute_set attr_set;
219 typedef logging::attribute_value_set attr_values;
220 typedef logging::filter filter;
221 typedef test_data< char > data;
222
223 attrs::constant< int > attr1(10);
224 attrs::constant< double > attr2(5.5);
225 attrs::constant< std::string > attr3("Hello, world!");
226
227 attr_set set1, set2, set3;
228 set1[data::attr1()] = attr1;
229 set1[data::attr2()] = attr2;
230 set1[data::attr3()] = attr3;
231
232 attr_values values1(set1, set2, set3);
233 values1.freeze();
234
235 filter f = expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
236 BOOST_CHECK(f(values1));
237
238 f = expr::begins_with(expr::attr< std::string >(data::attr3()), "hello");
239 BOOST_CHECK(!f(values1));
240
241 f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
242 BOOST_CHECK(!f(values1));
243
244 f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
245 BOOST_CHECK(!f(values1));
246
247 f = expr::begins_with(expr::attr< std::string >(data::attr2()), "Hello");
248 BOOST_CHECK(!f(values1));
249
250 f = expr::begins_with(expr::attr< std::string >(data::attr4()), "Hello");
251 BOOST_CHECK(!f(values1));
252 }
253
254 // The test checks that ends_with condition works
BOOST_AUTO_TEST_CASE(ends_with_check)255 BOOST_AUTO_TEST_CASE(ends_with_check)
256 {
257 typedef logging::attribute_set attr_set;
258 typedef logging::attribute_value_set attr_values;
259 typedef logging::filter filter;
260 typedef test_data< char > data;
261
262 attrs::constant< int > attr1(10);
263 attrs::constant< double > attr2(5.5);
264 attrs::constant< std::string > attr3("Hello, world!");
265
266 attr_set set1, set2, set3;
267 set1[data::attr1()] = attr1;
268 set1[data::attr2()] = attr2;
269 set1[data::attr3()] = attr3;
270
271 attr_values values1(set1, set2, set3);
272 values1.freeze();
273
274 filter f = expr::ends_with(expr::attr< std::string >(data::attr3()), "world!");
275 BOOST_CHECK(f(values1));
276
277 f = expr::ends_with(expr::attr< std::string >(data::attr3()), "World!");
278 BOOST_CHECK(!f(values1));
279
280 f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
281 BOOST_CHECK(!f(values1));
282
283 f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Hello");
284 BOOST_CHECK(!f(values1));
285
286 f = expr::ends_with(expr::attr< std::string >(data::attr2()), "world!");
287 BOOST_CHECK(!f(values1));
288
289 f = expr::ends_with(expr::attr< std::string >(data::attr4()), "world!");
290 BOOST_CHECK(!f(values1));
291 }
292
293 // The test checks that contains condition works
BOOST_AUTO_TEST_CASE(contains_check)294 BOOST_AUTO_TEST_CASE(contains_check)
295 {
296 typedef logging::attribute_set attr_set;
297 typedef logging::attribute_value_set attr_values;
298 typedef logging::filter filter;
299 typedef test_data< char > data;
300
301 attrs::constant< int > attr1(10);
302 attrs::constant< double > attr2(5.5);
303 attrs::constant< std::string > attr3("Hello, world!");
304
305 attr_set set1, set2, set3;
306 set1[data::attr1()] = attr1;
307 set1[data::attr2()] = attr2;
308 set1[data::attr3()] = attr3;
309
310 attr_values values1(set1, set2, set3);
311 values1.freeze();
312
313 filter f = expr::contains(expr::attr< std::string >(data::attr3()), "Hello");
314 BOOST_CHECK(f(values1));
315
316 f = expr::contains(expr::attr< std::string >(data::attr3()), "hello");
317 BOOST_CHECK(!f(values1));
318
319 f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "o, w");
320 BOOST_CHECK(f(values1));
321
322 f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
323 BOOST_CHECK(f(values1));
324
325 f = expr::contains(expr::attr< std::string >(data::attr2()), "Hello");
326 BOOST_CHECK(!f(values1));
327
328 f = expr::contains(expr::attr< std::string >(data::attr4()), "Hello");
329 BOOST_CHECK(!f(values1));
330 }
331
332 // The test checks that matches condition works
BOOST_AUTO_TEST_CASE(matches_check)333 BOOST_AUTO_TEST_CASE(matches_check)
334 {
335 typedef logging::attribute_set attr_set;
336 typedef logging::attribute_value_set attr_values;
337 typedef logging::filter filter;
338 typedef test_data< char > data;
339
340 attrs::constant< int > attr1(10);
341 attrs::constant< double > attr2(5.5);
342 attrs::constant< std::string > attr3("Hello, world!");
343
344 attr_set set1, set2, set3;
345 set1[data::attr1()] = attr1;
346 set1[data::attr2()] = attr2;
347 set1[data::attr3()] = attr3;
348
349 attr_values values1(set1, set2, set3);
350 values1.freeze();
351
352 boost::regex rex("hello");
353 filter f = expr::matches(expr::attr< std::string >(data::attr3()), rex);
354 BOOST_CHECK(!f(values1));
355
356 rex = ".*world.*";
357 f = expr::matches(expr::attr< std::string >(data::attr3()).or_throw(), rex);
358 BOOST_CHECK(f(values1));
359
360 rex = ".*";
361 f = expr::matches(expr::attr< std::string >(data::attr2()), rex);
362 BOOST_CHECK(!f(values1));
363
364 f = expr::matches(expr::attr< std::string >(data::attr4()), rex);
365 BOOST_CHECK(!f(values1));
366 }
367
368 // The test checks that the filter composition works
BOOST_AUTO_TEST_CASE(composition_check)369 BOOST_AUTO_TEST_CASE(composition_check)
370 {
371 typedef logging::attribute_set attr_set;
372 typedef logging::attribute_value_set attr_values;
373 typedef logging::filter filter;
374 typedef test_data< char > data;
375
376 attrs::constant< int > attr1(10);
377 attrs::constant< double > attr2(5.5);
378 attrs::constant< std::string > attr3("Hello, world!");
379
380 attr_set set1, set2, set3;
381 attr_values values1(set1, set2, set3);
382 values1.freeze();
383 set1[data::attr2()] = attr2;
384 attr_values values2(set1, set2, set3);
385 values2.freeze();
386 set1[data::attr3()] = attr3;
387 set1[data::attr1()] = attr1;
388 attr_values values3(set1, set2, set3);
389 values3.freeze();
390
391 filter f =
392 expr::attr< int >(data::attr1()) <= 10 ||
393 expr::is_in_range(expr::attr< double >(data::attr2()), 2.2, 7.7);
394 BOOST_CHECK(!f(values1));
395 BOOST_CHECK(f(values2));
396 BOOST_CHECK(f(values3));
397
398 f = expr::attr< int >(data::attr1()) == 10 &&
399 expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
400 BOOST_CHECK(!f(values1));
401 BOOST_CHECK(!f(values2));
402 BOOST_CHECK(f(values3));
403 }
404