summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/log/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
commit483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch)
treee5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/log/test
parentInitial commit. (diff)
downloadceph-upstream.tar.xz
ceph-upstream.zip
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/log/test')
-rw-r--r--src/boost/libs/log/test/Jamfile.v2123
-rw-r--r--src/boost/libs/log/test/common/attr_comparison.hpp60
-rw-r--r--src/boost/libs/log/test/common/char_definitions.hpp116
-rw-r--r--src/boost/libs/log/test/common/make_record.hpp32
-rw-r--r--src/boost/libs/log/test/common/test_sink.hpp92
-rw-r--r--src/boost/libs/log/test/compile/current_function_support.cpp37
-rw-r--r--src/boost/libs/log/test/compile/self_contained_header.cpp22
-rw-r--r--src/boost/libs/log/test/compile/src_logger_assignable.cpp39
-rw-r--r--src/boost/libs/log/test/compile/src_logger_get_attributes.cpp44
-rw-r--r--src/boost/libs/log/test/compile/util_unique_identifier.cpp34
-rw-r--r--src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp42
-rw-r--r--src/boost/libs/log/test/performance/Jamfile.v215
-rw-r--r--src/boost/libs/log/test/performance/dump.cpp76
-rw-r--r--src/boost/libs/log/test/performance/record_emission.cpp132
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_set.cpp280
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp51
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_impl.cpp153
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_set.cpp244
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp60
-rw-r--r--src/boost/libs/log/test/run/attr_function.cpp138
-rw-r--r--src/boost/libs/log/test/run/attr_named_scope.cpp190
-rw-r--r--src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp101
-rw-r--r--src/boost/libs/log/test/run/attr_value_visitation.cpp238
-rw-r--r--src/boost/libs/log/test/run/core.cpp243
-rw-r--r--src/boost/libs/log/test/run/filt_attr.cpp403
-rw-r--r--src/boost/libs/log/test/run/filt_has_attr.cpp102
-rw-r--r--src/boost/libs/log/test/run/filt_matches_boost_regex.cpp107
-rw-r--r--src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp115
-rw-r--r--src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp114
-rw-r--r--src/boost/libs/log/test/run/filt_matches_std_regex.cpp120
-rw-r--r--src/boost/libs/log/test/run/filt_matches_xpressive.cpp107
-rw-r--r--src/boost/libs/log/test/run/form_attr.cpp123
-rw-r--r--src/boost/libs/log/test/run/form_auto_newline.cpp94
-rw-r--r--src/boost/libs/log/test/run/form_c_decor.cpp126
-rw-r--r--src/boost/libs/log/test/run/form_char_decor.cpp174
-rw-r--r--src/boost/libs/log/test/run/form_csv_decor.cpp84
-rw-r--r--src/boost/libs/log/test/run/form_date_time.cpp212
-rw-r--r--src/boost/libs/log/test/run/form_format.cpp83
-rw-r--r--src/boost/libs/log/test/run/form_if.cpp107
-rw-r--r--src/boost/libs/log/test/run/form_max_size_decor.cpp177
-rw-r--r--src/boost/libs/log/test/run/form_message.cpp84
-rw-r--r--src/boost/libs/log/test/run/form_named_scope.cpp537
-rw-r--r--src/boost/libs/log/test/run/form_to_log_manip.cpp98
-rw-r--r--src/boost/libs/log/test/run/form_xml_decor.cpp84
-rw-r--r--src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp67
-rw-r--r--src/boost/libs/log/test/run/src_record_ostream.cpp479
-rw-r--r--src/boost/libs/log/test/run/util_dynamic_type_disp.cpp138
-rw-r--r--src/boost/libs/log/test/run/util_exception_handler.cpp361
-rw-r--r--src/boost/libs/log/test/run/util_formatting_ostream.cpp503
-rw-r--r--src/boost/libs/log/test/run/util_ipc_object_name.cpp177
-rw-r--r--src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp474
-rw-r--r--src/boost/libs/log/test/run/util_manip_add_value.cpp139
-rw-r--r--src/boost/libs/log/test/run/util_manip_auto_newline.cpp83
-rw-r--r--src/boost/libs/log/test/run/util_manip_dump.cpp239
-rw-r--r--src/boost/libs/log/test/run/util_manip_to_log.cpp134
-rw-r--r--src/boost/libs/log/test/run/util_once_block.cpp293
-rw-r--r--src/boost/libs/log/test/run/util_static_type_disp.cpp147
-rw-r--r--src/boost/libs/log/test/run/util_stp_filter_parser.cpp808
-rw-r--r--src/boost/libs/log/test/run/util_stp_formatter_parser.cpp257
-rw-r--r--src/boost/libs/log/test/run/util_stp_settings_parser.cpp294
-rw-r--r--src/boost/libs/log/test/run/util_string_literal.cpp221
61 files changed, 10427 insertions, 0 deletions
diff --git a/src/boost/libs/log/test/Jamfile.v2 b/src/boost/libs/log/test/Jamfile.v2
new file mode 100644
index 00000000..11246932
--- /dev/null
+++ b/src/boost/libs/log/test/Jamfile.v2
@@ -0,0 +1,123 @@
+#
+# 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)
+#
+# The file was adapted from libs/tr2/test/Jamfile.v2 by John Maddock.
+
+import testing ;
+import path ;
+import regex ;
+import os ;
+import ../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <include>common
+
+ # Disable warnings about using 'insecure' standard C functions
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>msvc:<cxxflags>/wd4355 # 'this' : used in base member initializer list
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76
+ <target-os>cygwin:<define>BOOST_LOG_WITHOUT_IPC
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/regex//boost_regex
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/test//boost_unit_test_framework
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ : default-build
+ # Testers typically don't specify threading environment and the library can be built and tested for single and multi. I'm more interested in multi though.
+ <threading>multi
+# <link>static
+ ;
+
+# this rule enumerates through all the sources and invokes
+# the run rule for each source, the result is a list of all
+# the run rules, which we can pass on to the test_suite rule:
+rule test_all
+{
+ local all_rules ;
+ local file ;
+
+ if ! [ os.environ BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ]
+ {
+ local headers_path = [ path.make $(BOOST_ROOT)/libs/log/include/boost/log ] ;
+ for file in [ path.glob-tree $(headers_path) : *.hpp : detail ]
+ {
+ local rel_file = [ path.relative-to $(headers_path) $(file) ] ;
+ # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end.
+ # All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes.
+ local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ;
+ #ECHO $(rel_file) ;
+ all_rules += [ compile compile/self_contained_header.cpp : <define>"BOOST_LOG_TEST_HEADER=$(rel_file)" <dependency>$(file) : $(test_name) ] ;
+ }
+ }
+
+ for file in [ glob compile/*.cpp ]
+ {
+ if [ path.basename $(file) ] != "self_contained_header.cpp"
+ {
+ all_rules += [ compile $(file) ] ;
+ }
+ }
+ for file in [ glob compile_fail/*.cpp ]
+ {
+ all_rules += [ compile-fail $(file) ] ;
+ }
+ for file in [ glob run/*.cpp ]
+ {
+ all_rules += [ run $(file) ] ;
+ }
+
+ if ! [ os.environ BOOST_LOG_TEST_WITHOUT_EXAMPLES ]
+ {
+ all_rules += [ build-project ../example ] ;
+ }
+
+ #ECHO All rules: $(all_rules) ;
+ return $(all_rules) ;
+}
+
+test-suite log : [ test_all ] ;
diff --git a/src/boost/libs/log/test/common/attr_comparison.hpp b/src/boost/libs/log/test/common/attr_comparison.hpp
new file mode 100644
index 00000000..b4be4f48
--- /dev/null
+++ b/src/boost/libs/log/test/common/attr_comparison.hpp
@@ -0,0 +1,60 @@
+/*
+ * 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 attr_comparison.hpp
+ * \author Andrey Semashev
+ * \date 06.08.2010
+ *
+ * \brief This header contains tools for attribute comparison in attribute-related tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
+
+#include <ostream>
+#include <boost/log/attributes/attribute.hpp>
+
+class attribute_factory_helper :
+ public boost::log::attribute
+{
+ typedef boost::log::attribute base_type;
+
+public:
+ attribute_factory_helper(base_type const& that) : base_type(that)
+ {
+ }
+
+ impl* get_impl() const
+ {
+ return base_type::get_impl();
+ }
+};
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+inline bool operator== (attribute const& left, attribute const& right)
+{
+ return attribute_factory_helper(left).get_impl() == attribute_factory_helper(right).get_impl();
+}
+inline bool operator!= (attribute const& left, attribute const& right)
+{
+ return attribute_factory_helper(left).get_impl() != attribute_factory_helper(right).get_impl();
+}
+
+inline std::ostream& operator<< (std::ostream& strm, attribute const& val)
+{
+ strm << attribute_factory_helper(val).get_impl();
+ return strm;
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/char_definitions.hpp b/src/boost/libs/log/test/common/char_definitions.hpp
new file mode 100644
index 00000000..2cf0d664
--- /dev/null
+++ b/src/boost/libs/log/test/common/char_definitions.hpp
@@ -0,0 +1,116 @@
+/*
+ * 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 char_definitions.hpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains common type definitions for character type dependent tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
+
+#include <string>
+#include <iostream>
+#include <boost/mpl/vector.hpp>
+
+namespace mpl = boost::mpl;
+
+typedef mpl::vector<
+#ifdef BOOST_LOG_USE_CHAR
+ char
+#endif
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+ ,
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+ wchar_t
+#endif
+>::type char_types;
+
+template< typename >
+struct test_data;
+
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template< >
+struct test_data< char >
+{
+ static const char* abc() { return "abc"; }
+ static const char* ABC() { return "ABC"; }
+ static const char* some_test_string() { return "some test string"; }
+ static const char* zero_to_five() { return "012345"; }
+ static const char* def() { return "def"; }
+ static const char* aaa() { return "aaa"; }
+ static const char* abcd() { return "abcd"; }
+ static const char* zz() { return "zz"; }
+ static const char* abcdefg0123456789() { return "abcdefg0123456789"; }
+
+ static const char* attr1() { return "attr1"; }
+ static const char* attr2() { return "attr2"; }
+ static const char* attr3() { return "attr3"; }
+ static const char* attr4() { return "attr4"; }
+
+ static const char* int_format1() { return "%08d"; }
+ static const char* fp_format1() { return "%06.3f"; }
+};
+
+//! The function compares two strings and prints them if they are not equal
+inline bool equal_strings(std::string const& left, std::string const& right)
+{
+ if (left != right)
+ {
+ std::cout << "Left: \"" << left << "\"\nRight: \"" << right << "\"" << std::endl;
+ return false;
+ }
+ else
+ return true;
+}
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template< >
+struct test_data< wchar_t >
+{
+ static const wchar_t* abc() { return L"abc"; }
+ static const wchar_t* ABC() { return L"ABC"; }
+ static const wchar_t* some_test_string() { return L"some test string"; }
+ static const wchar_t* zero_to_five() { return L"012345"; }
+ static const wchar_t* def() { return L"def"; }
+ static const wchar_t* aaa() { return L"aaa"; }
+ static const wchar_t* abcd() { return L"abcd"; }
+ static const wchar_t* zz() { return L"zz"; }
+ static const wchar_t* abcdefg0123456789() { return L"abcdefg0123456789"; }
+
+ static const char* attr1() { return "attr1"; }
+ static const char* attr2() { return "attr2"; }
+ static const char* attr3() { return "attr3"; }
+ static const char* attr4() { return "attr4"; }
+
+ static const wchar_t* int_format1() { return L"%08d"; }
+ static const wchar_t* fp_format1() { return L"%06.3f"; }
+};
+
+//! The function compares two strings and prints them if they are not equal
+inline bool equal_strings(std::wstring const& left, std::wstring const& right)
+{
+ if (left != right)
+ {
+ std::wcout << L"Left: \"" << left << L"\"\nRight: \"" << right << L"\"" << std::endl;
+ return false;
+ }
+ else
+ return true;
+}
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+#endif // BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/make_record.hpp b/src/boost/libs/log/test/common/make_record.hpp
new file mode 100644
index 00000000..9d1f028d
--- /dev/null
+++ b/src/boost/libs/log/test/common/make_record.hpp
@@ -0,0 +1,32 @@
+/*
+ * 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 make_record.hpp
+ * \author Andrey Semashev
+ * \date 18.03.2009
+ *
+ * \brief This header contains a helper function make_record that creates a log record with the specified attributes.
+ */
+
+#ifndef BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
+
+#include <boost/move/utility_core.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+
+inline boost::log::record make_record(boost::log::attribute_set const& src_attrs = boost::log::attribute_set())
+{
+ return boost::log::core::get()->open_record(src_attrs);
+}
+
+inline boost::log::record_view make_record_view(boost::log::attribute_set const& src_attrs = boost::log::attribute_set())
+{
+ return make_record(src_attrs).lock();
+}
+
+#endif // BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/test_sink.hpp b/src/boost/libs/log/test/common/test_sink.hpp
new file mode 100644
index 00000000..da88830e
--- /dev/null
+++ b/src/boost/libs/log/test/common/test_sink.hpp
@@ -0,0 +1,92 @@
+/*
+ * 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 test_sink.hpp
+ * \author Andrey Semashev
+ * \date 18.03.2009
+ *
+ * \brief This header contains a test sink frontend that is used through various tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
+
+#include <cstddef>
+#include <map>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/expressions/filter.hpp>
+
+//! A sink implementation for testing purpose
+struct test_sink :
+ public boost::log::sinks::sink
+{
+public:
+ typedef boost::log::attribute_value_set attribute_values;
+ typedef boost::log::record_view record_type;
+ typedef boost::log::filter filter_type;
+ typedef attribute_values::key_type key_type;
+
+ struct key_type_order
+ {
+ typedef bool result_type;
+
+ result_type operator() (key_type const& left, key_type const& right) const
+ {
+ return left.id() < right.id();
+ }
+ };
+
+ typedef std::map< key_type, std::size_t, key_type_order > attr_counters_map;
+
+public:
+ filter_type m_Filter;
+ attr_counters_map m_Consumed;
+ std::size_t m_RecordCounter;
+
+public:
+ test_sink() : boost::log::sinks::sink(false), m_RecordCounter(0) {}
+
+ void set_filter(filter_type const& f)
+ {
+ m_Filter = f;
+ }
+
+ void reset_filter()
+ {
+ m_Filter.reset();
+ }
+
+ bool will_consume(attribute_values const& attributes)
+ {
+ return m_Filter(attributes);
+ }
+
+ void consume(record_type const& record)
+ {
+ ++m_RecordCounter;
+ attribute_values::const_iterator
+ it = record.attribute_values().begin(),
+ end = record.attribute_values().end();
+ for (; it != end; ++it)
+ ++m_Consumed[it->first];
+ }
+
+ void flush()
+ {
+ }
+
+ void clear()
+ {
+ m_RecordCounter = 0;
+ m_Consumed.clear();
+ }
+};
+
+#endif // BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/compile/current_function_support.cpp b/src/boost/libs/log/test/compile/current_function_support.cpp
new file mode 100644
index 00000000..cdcd1051
--- /dev/null
+++ b/src/boost/libs/log/test/compile/current_function_support.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 current_function_support.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2010
+ *
+ * \brief This test checks that the BOOST_CURRENT_FUNCTION macro has semantics
+ * compatible with Boost.Log on the current platform.
+ *
+ * The point of this test is to determine whether the macro unfolds into a string literal
+ * rather than a pointer to a string. This is critical because BOOST_LOG_WFUNCTION
+ * relies on this fact - it determines the length of the literal by applying sizeof to it.
+ */
+
+#define BOOST_TEST_MODULE current_function_support
+
+#include <boost/current_function.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_array.hpp>
+
+template< typename T >
+void check(T& param)
+{
+ BOOST_STATIC_ASSERT(boost::is_array< T >::value);
+}
+
+int main(int, char*[])
+{
+ check(BOOST_CURRENT_FUNCTION);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/self_contained_header.cpp b/src/boost/libs/log/test/compile/self_contained_header.cpp
new file mode 100644
index 00000000..8e3a2c5a
--- /dev/null
+++ b/src/boost/libs/log/test/compile/self_contained_header.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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 self_contained_header.cpp
+ * \author Andrey Semashev
+ * \date 15.03.2014
+ *
+ * \brief This file contains a test boilerplate for checking that every public header is self-contained and does not have any missing #includes.
+ */
+
+#define BOOST_LOG_TEST_INCLUDE_HEADER() <boost/log/BOOST_LOG_TEST_HEADER>
+
+#include BOOST_LOG_TEST_INCLUDE_HEADER()
+
+int main(int, char*[])
+{
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/src_logger_assignable.cpp b/src/boost/libs/log/test/compile/src_logger_assignable.cpp
new file mode 100644
index 00000000..d1d51f57
--- /dev/null
+++ b/src/boost/libs/log/test/compile/src_logger_assignable.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 src_logger_assignable.cpp
+ * \author Andrey Semashev
+ * \date 16.05.2011
+ *
+ * \brief This header contains a test for logger assignability.
+ */
+
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+#include <boost/log/sources/channel_logger.hpp>
+#include <boost/log/sources/severity_channel_logger.hpp>
+
+template< typename LoggerT >
+void test()
+{
+ LoggerT lg1, lg2;
+
+ // Loggers must be assignable. The assignment operator must be taken
+ // from the composite_logger class and not auto-generated (in which
+ // case it will fail to compile because assignment in basic_logger is private).
+ lg1 = lg2;
+}
+
+int main(int, char*[])
+{
+ test< boost::log::sources::logger >();
+ test< boost::log::sources::severity_logger< > >();
+ test< boost::log::sources::channel_logger< > >();
+ test< boost::log::sources::severity_channel_logger< > >();
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp b/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp
new file mode 100644
index 00000000..b837917a
--- /dev/null
+++ b/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 src_logger_get_attributes.cpp
+ * \author Andrey Semashev
+ * \date 01.03.2014
+ *
+ * \brief This header contains a test for logger \c get_attributes method.
+ */
+
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+#include <boost/log/sources/channel_logger.hpp>
+#include <boost/log/sources/severity_channel_logger.hpp>
+
+template< typename LoggerT >
+void test()
+{
+ LoggerT lg;
+
+ // Test that get_attributes(), which is a const method, can acquire the internal mutex in the threading model.
+ lg.get_attributes();
+}
+
+int main(int, char*[])
+{
+ test< boost::log::sources::logger >();
+ test< boost::log::sources::severity_logger< > >();
+ test< boost::log::sources::channel_logger< > >();
+ test< boost::log::sources::severity_channel_logger< > >();
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ test< boost::log::sources::logger_mt >();
+ test< boost::log::sources::severity_logger_mt< > >();
+ test< boost::log::sources::channel_logger_mt< > >();
+ test< boost::log::sources::severity_channel_logger_mt< > >();
+#endif
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/util_unique_identifier.cpp b/src/boost/libs/log/test/compile/util_unique_identifier.cpp
new file mode 100644
index 00000000..50e7ee03
--- /dev/null
+++ b/src/boost/libs/log/test/compile/util_unique_identifier.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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_unique_identifier.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the unique identifier name generator.
+ */
+
+#include <boost/log/utility/unique_identifier_name.hpp>
+
+// Some hints to avoid warnings about unused variables in this test
+#if defined(__GNUC__)
+#define BOOST_LOG_AUX_UNUSED_ATTR __attribute__((unused))
+#else
+#define BOOST_LOG_AUX_UNUSED_ATTR
+#endif
+
+int main(int, char*[])
+{
+ // Names with the same prefixes may coexist in different lines
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var) = 0;
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var) = 0;
+
+ // Names with different prefixes may coexist on the same line
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var1) = 0; BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var2) = 0;
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp b/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp
new file mode 100644
index 00000000..5ad7a599
--- /dev/null
+++ b/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 attr_functor_void_return.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This test checks that it is not possible to create a functor attribute
+ * with a void-returning functor.
+ */
+
+#define BOOST_TEST_MODULE attr_functor_void_return
+
+#include <boost/utility/result_of.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/function.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // A test function that returns an attribute value
+ void get_attr_value() {}
+
+} // namespace
+
+int main(int, char*[])
+{
+ logging::attribute attr1 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(&get_attr_value);
+#else
+ attrs::make_function< void >(&get_attr_value);
+#endif
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/performance/Jamfile.v2 b/src/boost/libs/log/test/performance/Jamfile.v2
new file mode 100644
index 00000000..036ed6e0
--- /dev/null
+++ b/src/boost/libs/log/test/performance/Jamfile.v2
@@ -0,0 +1,15 @@
+#
+# 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)
+#
+
+exe record_emission
+ : record_emission.cpp ../../build//boost_log
+ ;
+
+exe dump
+ : dump.cpp ../../build//boost_log
+ ;
+
diff --git a/src/boost/libs/log/test/performance/dump.cpp b/src/boost/libs/log/test/performance/dump.cpp
new file mode 100644
index 00000000..b19b161a
--- /dev/null
+++ b/src/boost/libs/log/test/performance/dump.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 dump.cpp
+ * \author Andrey Semashev
+ * \date 05.05.2013
+ *
+ * \brief This code measures performance dumping binary data
+ */
+
+#include <cstdlib>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/cstdint.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+
+namespace logging = boost::log;
+
+const unsigned int base_loop_count = 10000;
+
+void test(std::size_t block_size)
+{
+ std::cout << "Block size: " << block_size << " bytes.";
+
+ std::vector< boost::uint8_t > data;
+ data.resize(block_size);
+ std::generate_n(data.begin(), block_size, &std::rand);
+
+ std::string str;
+ logging::formatting_ostream strm(str);
+
+ const boost::uint8_t* const p = &data[0];
+
+ boost::uint64_t data_processed = 0, duration = 0;
+ boost::posix_time::ptime start, end;
+ start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ do
+ {
+ for (unsigned int i = 0; i < base_loop_count; ++i)
+ {
+ strm << logging::dump(p, block_size);
+ str.clear();
+ }
+ end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ data_processed += base_loop_count * block_size;
+ duration = (end - start).total_microseconds();
+ }
+ while (duration < 2000000);
+
+ std::cout << " Test duration: " << duration << " us ("
+ << std::fixed << std::setprecision(3) << static_cast< double >(data_processed) / (static_cast< double >(duration) * (1048576.0 / 1000000.0))
+ << " MiB per second)" << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ test(32);
+ test(128);
+ test(1024);
+ test(16384);
+ test(1048576);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/performance/record_emission.cpp b/src/boost/libs/log/test/performance/record_emission.cpp
new file mode 100644
index 00000000..8657091c
--- /dev/null
+++ b/src/boost/libs/log/test/performance/record_emission.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 record_emission.cpp
+ * \author Andrey Semashev
+ * \date 22.03.2009
+ *
+ * \brief This code measures performance of log record emission
+ */
+
+// #define BOOST_LOG_USE_CHAR
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+#define BOOST_NO_DYN_LINK 1
+
+#include <iomanip>
+#include <iostream>
+#include <boost/ref.hpp>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/log/core.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sinks/basic_sink_backend.hpp>
+#include <boost/log/sources/logger.hpp>
+
+#include <boost/log/expressions.hpp>
+
+#include <boost/log/attributes/scoped_attribute.hpp>
+
+enum config
+{
+ RECORD_COUNT = 20000000,
+ THREAD_COUNT = 8,
+ SINK_COUNT = 3
+};
+
+namespace logging = boost::log;
+namespace expr = boost::log::expressions;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace keywords = boost::log::keywords;
+
+enum severity_level
+{
+ normal,
+ warning,
+ error
+};
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
+
+namespace {
+
+ //! A fake sink backend that receives log records
+ class fake_backend :
+ public sinks::basic_sink_backend< sinks::concurrent_feeding >
+ {
+ public:
+ void consume(logging::record_view const& rec)
+ {
+ }
+ };
+
+} // namespace
+
+void test(unsigned int record_count, boost::barrier& bar)
+{
+ BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
+ src::severity_logger< severity_level > slg;
+// src::logger lg;
+ bar.wait();
+
+ for (unsigned int i = 0; i < record_count; ++i)
+ {
+ BOOST_LOG_SEV(slg, warning) << "Test record";
+// BOOST_LOG(lg) << "Test record";
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ std::cout << "Test config: " << THREAD_COUNT << " threads, " << SINK_COUNT << " sinks, " << RECORD_COUNT << " records" << std::endl;
+//__debugbreak();
+// typedef sinks::unlocked_sink< fake_backend > fake_sink;
+// typedef sinks::synchronous_sink< fake_backend > fake_sink;
+ typedef sinks::asynchronous_sink< fake_backend > fake_sink;
+ for (unsigned int i = 0; i < SINK_COUNT; ++i)
+ logging::core::get()->add_sink(boost::make_shared< fake_sink >());
+
+ logging::core::get()->add_global_attribute("LineID", attrs::counter< unsigned int >(1));
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("Scope", attrs::named_scope());
+
+// logging::core::get()->set_filter(severity > normal); // all records pass the filter
+// logging::core::get()->set_filter(severity > error); // all records don't pass the filter
+
+// logging::core::get()->set_filter(severity > error); // all records don't pass the filter
+
+ const unsigned int record_count = RECORD_COUNT / THREAD_COUNT;
+ boost::barrier bar(THREAD_COUNT);
+ boost::thread_group threads;
+
+ for (unsigned int i = 1; i < THREAD_COUNT; ++i)
+ threads.create_thread(boost::bind(&test, record_count, boost::ref(bar)));
+
+ boost::posix_time::ptime start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(), end;
+ test(record_count, bar);
+ if (THREAD_COUNT > 1)
+ threads.join_all();
+ end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+
+ unsigned long long duration = (end - start).total_microseconds();
+
+ std::cout << "Test duration: " << duration << " us ("
+ << std::fixed << std::setprecision(3) << static_cast< double >(RECORD_COUNT) / (static_cast< double >(duration) / 1000000.0)
+ << " records per second)" << std::endl;
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_set.cpp b/src/boost/libs/log/test/run/attr_attribute_set.cpp
new file mode 100644
index 00000000..669f4d09
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_set.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 attr_attribute_set.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the attribute set class.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_set
+
+#include <list>
+#include <vector>
+#include <string>
+#include <utility>
+#include <iterator>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include "char_definitions.hpp"
+#include "attr_comparison.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+// The test checks construction and assignment
+BOOST_AUTO_TEST_CASE(construction)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ BOOST_CHECK(set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 0UL);
+
+ attr_set set2 = set1;
+ BOOST_CHECK(set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 0UL);
+
+ set2[data::attr1()] = attr1;
+ set2[data::attr2()] = attr2;
+ BOOST_CHECK(set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 0UL);
+ BOOST_CHECK(!set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+
+ attr_set set3 = set2;
+ BOOST_CHECK(!set3.empty());
+ BOOST_CHECK_EQUAL(set3.size(), 2UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr2()), 1UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr3()), 0UL);
+
+ set1[data::attr3()] = attr3;
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr3()), 1UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set1.size(), set2.size());
+ BOOST_CHECK(std::equal(set1.begin(), set1.end(), set2.begin()));
+}
+
+// The test checks lookup methods
+BOOST_AUTO_TEST_CASE(lookup)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ // Traditional find methods
+ attr_set::iterator it = set1.find(data::attr1());
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+
+ string s1 = data::attr2();
+ it = set1.find(s1);
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr2);
+
+ it = set1.find(data::attr1());
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+
+ it = set1.find(data::attr3());
+ BOOST_CHECK(it == set1.end());
+
+ // Subscript operator
+ logging::attribute p = set1[data::attr1()];
+ BOOST_CHECK_EQUAL(p, attr1);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[s1];
+ BOOST_CHECK_EQUAL(p, attr2);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[data::attr1()];
+ BOOST_CHECK_EQUAL(p, attr1);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[data::attr3()];
+ BOOST_CHECK(!p);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Counting elements
+ BOOST_CHECK_EQUAL(set1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(s1), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr3()), 0UL);
+}
+
+// The test checks insertion methods
+BOOST_AUTO_TEST_CASE(insertion)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+
+ // Traditional insert methods
+ std::pair< attr_set::iterator, bool > res = set1.insert(data::attr1(), attr1);
+ BOOST_CHECK(res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr1());
+ BOOST_CHECK_EQUAL(res.first->second, attr1);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 1UL);
+
+ res = set1.insert(std::make_pair(attr_set::key_type(data::attr2()), attr2));
+ BOOST_CHECK(res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr2());
+ BOOST_CHECK_EQUAL(res.first->second, attr2);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Insertion attempt of an attribute with the name of an already existing attribute
+ res = set1.insert(std::make_pair(attr_set::key_type(data::attr2()), attr3));
+ BOOST_CHECK(!res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr2());
+ BOOST_CHECK_EQUAL(res.first->second, attr2);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Mass insertion
+ typedef attr_set::key_type key_type;
+ std::list< std::pair< key_type, logging::attribute > > elems;
+ elems.push_back(std::make_pair(key_type(data::attr2()), attr2));
+ elems.push_back(std::make_pair(key_type(data::attr1()), attr1));
+ elems.push_back(std::make_pair(key_type(data::attr3()), attr3));
+ // ... with element duplication
+ elems.push_back(std::make_pair(key_type(data::attr1()), attr3));
+
+ attr_set set2;
+ set2.insert(elems.begin(), elems.end());
+ BOOST_CHECK(!set2.empty());
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+ typedef attr_set::mapped_type mapped_type;
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr1()]), attr1);
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr2()]), attr2);
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr3()]), attr3);
+
+ // The same, but with insertion results collection
+ std::vector< std::pair< attr_set::iterator, bool > > results;
+
+ attr_set set3;
+ set3.insert(elems.begin(), elems.end(), std::back_inserter(results));
+ BOOST_REQUIRE_EQUAL(results.size(), elems.size());
+ BOOST_CHECK(!set3.empty());
+ BOOST_REQUIRE_EQUAL(set3.size(), 3UL);
+ attr_set::iterator it = set3.find(data::attr1());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr1());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+ BOOST_CHECK(it == results[1].first);
+ it = set3.find(data::attr2());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr2());
+ BOOST_CHECK_EQUAL(it->second, attr2);
+ BOOST_CHECK(it == results[0].first);
+ it = set3.find(data::attr3());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr3());
+ BOOST_CHECK_EQUAL(it->second, attr3);
+ BOOST_CHECK(it == results[2].first);
+
+ BOOST_CHECK(results[0].second);
+ BOOST_CHECK(results[1].second);
+ BOOST_CHECK(results[2].second);
+ BOOST_CHECK(!results[3].second);
+
+ // Subscript operator
+ attr_set set4;
+
+ logging::attribute& p1 = (set4[data::attr1()] = attr1);
+ BOOST_CHECK_EQUAL(set4.size(), 1UL);
+ BOOST_CHECK_EQUAL(p1, attr1);
+
+ logging::attribute& p2 = (set4[string(data::attr2())] = attr2);
+ BOOST_CHECK_EQUAL(set4.size(), 2UL);
+ BOOST_CHECK_EQUAL(p2, attr2);
+
+ logging::attribute& p3 = (set4[key_type(data::attr3())] = attr3);
+ BOOST_CHECK_EQUAL(set4.size(), 3UL);
+ BOOST_CHECK_EQUAL(p3, attr3);
+
+ // subscript operator can replace existing elements
+ logging::attribute& p4 = (set4[data::attr3()] = attr1);
+ BOOST_CHECK_EQUAL(set4.size(), 3UL);
+ BOOST_CHECK_EQUAL(p4, attr1);
+}
+
+// The test checks erasure methods
+BOOST_AUTO_TEST_CASE(erasure)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_set set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ BOOST_CHECK_EQUAL(set2.erase(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr1()), 0UL);
+
+ BOOST_CHECK_EQUAL(set2.erase(data::attr1()), 0UL);
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+
+ set2.erase(set2.begin());
+ BOOST_CHECK_EQUAL(set2.size(), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr2()), 0UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ attr_set::iterator it = set2.begin();
+ set2.erase(++it, set2.end());
+ BOOST_CHECK_EQUAL(set2.size(), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr2()), 0UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr3()), 0UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ set2.clear();
+ BOOST_CHECK(set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 0UL);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp b/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp
new file mode 100644
index 00000000..142307d9
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 attr_attribute_set_ticket11106.cpp
+ * \author Andrey Semashev
+ * \date 15.03.2015
+ *
+ * \brief This header contains a test for the fix for https://svn.boost.org/trac/boost/ticket/11106.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_set_ticket11106
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+
+// The test checks that insertion does not invalidate existing elements in the container
+BOOST_AUTO_TEST_CASE(ticket11106)
+{
+ boost::log::attribute_set set;
+
+ unsigned int i = 0;
+ while (i < 100)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ boost::log::attribute_name name = strm.str();
+
+ std::pair< boost::log::attribute_set::iterator, bool > res = set.insert(name, boost::log::attributes::make_constant(5));
+ ++i;
+
+ BOOST_CHECK(res.second); // check that insertion succeeded
+ BOOST_CHECK(set.find(res.first->first) != set.end()); // check that lookup works
+
+ // Now check that all previously inserted elements are still findable
+ unsigned int j = 0;
+ for (boost::log::attribute_set::const_iterator it = set.begin(), end = set.end(); it != end; ++it, ++j)
+ {
+ boost::log::attribute_name key = it->first;
+ BOOST_CHECK(set.find(key) != set.end());
+ }
+ BOOST_CHECK_EQUAL(j, i);
+ }
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp b/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp
new file mode 100644
index 00000000..682b2e48
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 attr_attribute_value_impl.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the basic attribute value class.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_impl
+
+#include <string>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools//floating_point_comparison.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/attribute_value_impl.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+#include <boost/log/utility/functional/bind_assign.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_dispatcher() :
+ base_type(*this),
+ m_Expected(none_expected),
+ m_Int(0),
+ m_Double(0.0)
+ {
+ }
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test verifies that type dispatching works
+BOOST_AUTO_TEST_CASE(type_dispatching)
+{
+ my_dispatcher disp;
+ logging::attribute_value p1(attrs::make_attribute_value< int >(10));
+ logging::attribute_value p2(attrs::make_attribute_value< double > (5.5));
+ logging::attribute_value p3(attrs::make_attribute_value< std::string >(std::string("Hello, world!")));
+ logging::attribute_value p4(attrs::make_attribute_value< float >(static_cast< float >(-7.2)));
+
+ disp.set_expected(10);
+ BOOST_CHECK(p1.dispatch(disp));
+ BOOST_CHECK(p1.dispatch(disp)); // check that the contained value doesn't change over time or upon dispatching
+
+ disp.set_expected(5.5);
+ BOOST_CHECK(p2.dispatch(disp));
+
+ disp.set_expected("Hello, world!");
+ BOOST_CHECK(p3.dispatch(disp));
+
+ disp.set_expected();
+ BOOST_CHECK(!p4.dispatch(disp));
+}
+
+// The test verifies that value extraction works
+BOOST_AUTO_TEST_CASE(value_extraction)
+{
+ logging::attribute_value p1(attrs::make_attribute_value< int >(10));
+ logging::attribute_value p2(attrs::make_attribute_value< double >(5.5));
+
+ logging::value_ref< int > val1 = p1.extract< int >();
+ BOOST_CHECK(!!val1);
+ BOOST_CHECK_EQUAL(val1.get(), 10);
+
+ logging::value_ref< double > val2 = p1.extract< double >();
+ BOOST_CHECK(!val2);
+
+ double val3 = 0.0;
+ BOOST_CHECK(p2.visit< double >(logging::bind_assign(val3)));
+ BOOST_CHECK_CLOSE(val3, 5.5, 0.001);
+}
+
+// The test verifies that the detach_from_thread returns a valid pointer
+BOOST_AUTO_TEST_CASE(detaching_from_thread)
+{
+ boost::intrusive_ptr< logging::attribute_value::impl > p1(new attrs::attribute_value_impl< int >(10));
+ boost::intrusive_ptr< logging::attribute_value::impl > p2 = p1->detach_from_thread();
+ BOOST_CHECK(!!p2);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_set.cpp b/src/boost/libs/log/test/run/attr_attribute_value_set.cpp
new file mode 100644
index 00000000..1b806738
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_set.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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 attr_attribute_value_set.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the attribute value set.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_set
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <iterator>
+#include <boost/config.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools//floating_point_comparison.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ //! A simple attribute value receiver functional object
+ template< typename T >
+ struct receiver
+ {
+ typedef void result_type;
+ receiver(T& val) : m_Val(val) {}
+ result_type operator() (T const& val) const
+ {
+ m_Val = val;
+ }
+
+ private:
+ T& m_Val;
+ };
+
+ //! The function extracts attribute value
+ template< typename T >
+ inline bool get_attr_value(logging::attribute_value const& val, T& res)
+ {
+ receiver< T > r(res);
+ logging::static_type_dispatcher< T > disp(r);
+ return val.dispatch(disp);
+ }
+
+} // namespace
+
+// The test checks construction and assignment
+BOOST_AUTO_TEST_CASE(construction)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+ attrs::constant< char > attr4('L');
+
+ {
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ }
+ {
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set2[data::attr2()] = attr2;
+ set3[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+
+ attr_values view2 = view1;
+ BOOST_CHECK(!view2.empty());
+ BOOST_CHECK_EQUAL(view2.size(), 3UL);
+ }
+
+ // Check that the more prioritized attributes replace the less ones
+ {
+ attrs::constant< int > attr2_2(20);
+ attrs::constant< double > attr4_2(10.3);
+ attrs::constant< float > attr3_3(static_cast< float >(-7.2));
+ attrs::constant< unsigned int > attr4_3(5);
+
+ attr_set set1, set2, set3;
+ set3[data::attr1()] = attr1;
+ set3[data::attr2()] = attr2;
+ set3[data::attr3()] = attr3;
+ set3[data::attr4()] = attr4;
+
+ set2[data::attr2()] = attr2_2;
+ set2[data::attr4()] = attr4_2;
+
+ set1[data::attr3()] = attr3_3;
+ set1[data::attr4()] = attr4_3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 4UL);
+
+ int n = 0;
+ BOOST_CHECK(logging::visit< int >(data::attr1(), view1, receiver< int >(n)));
+ BOOST_CHECK_EQUAL(n, 10);
+
+ BOOST_CHECK(logging::visit< int >(data::attr2(), view1, receiver< int >(n)));
+ BOOST_CHECK_EQUAL(n, 20);
+
+ float f = static_cast< float >(0.0);
+ BOOST_CHECK(logging::visit< float >(data::attr3(), view1, receiver< float >(f)));
+ BOOST_CHECK_CLOSE(f, static_cast< float >(-7.2), static_cast< float >(0.001));
+
+ unsigned int m = 0;
+ BOOST_CHECK(logging::visit< unsigned int >(data::attr4(), view1, receiver< unsigned int >(m)));
+ BOOST_CHECK_EQUAL(m, 5U);
+ }
+}
+
+// The test checks lookup methods
+BOOST_AUTO_TEST_CASE(lookup)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ // Traditional find methods
+ attr_values::const_iterator it = view1.find(data::attr1());
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr1());
+ int val1 = 0;
+ BOOST_CHECK(get_attr_value(it->second, val1));
+ BOOST_CHECK_EQUAL(val1, 10);
+
+ string s1 = data::attr2();
+ it = view1.find(s1);
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr2());
+ double val2 = 0;
+ BOOST_CHECK(get_attr_value(it->second, val2));
+ BOOST_CHECK_CLOSE(val2, 5.5, 0.001);
+
+ it = view1.find(data::attr3());
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr3());
+ std::string val3;
+ BOOST_CHECK(get_attr_value(it->second, val3));
+ BOOST_CHECK_EQUAL(val3, "Hello, world!");
+
+ // make an additional check that the result is absent if the value type does not match the requested type
+ BOOST_CHECK(!get_attr_value(it->second, val2));
+
+ it = view1.find(data::attr4());
+ BOOST_CHECK(it == view1.end());
+
+ // Subscript operator
+ logging::attribute_value p = view1[data::attr1()];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val1));
+ BOOST_CHECK_EQUAL(val1, 10);
+
+ p = view1[s1];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val2));
+ BOOST_CHECK_CLOSE(val2, 5.5, 0.001);
+
+ p = view1[data::attr3()];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val3));
+ BOOST_CHECK_EQUAL(val3, "Hello, world!");
+
+ p = view1[data::attr4()];
+ BOOST_CHECK(!p);
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+
+ // Counting elements
+ BOOST_CHECK_EQUAL(view1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(s1), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(data::attr3()), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(data::attr4()), 0UL);
+}
+
+// The test checks size method
+BOOST_AUTO_TEST_CASE(size)
+{
+ typedef logging::attribute_value_set attr_values;
+ attrs::constant< int > attr1(10);
+
+ attr_values view;
+ view.freeze();
+
+ unsigned int i = 0;
+ for (; i < 100; ++i)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+
+ view.insert(attr_values::key_type(strm.str()), attr1.get_value());
+ }
+
+ BOOST_CHECK_EQUAL(view.size(), i);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp b/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp
new file mode 100644
index 00000000..d5a0388f
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 attr_attribute_value_set_ticket11190.cpp
+ * \author Andrey Semashev
+ * \date 25.04.2015
+ *
+ * \brief This header contains a test for the fix for https://svn.boost.org/trac/boost/ticket/11190.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_set_ticket11190
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+
+// The test checks that insertion does not invalidate existing elements in the container
+BOOST_AUTO_TEST_CASE(ticket11190)
+{
+ boost::log::attribute_set set, dummy;
+
+ unsigned int i = 0;
+ while (i < 100)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ boost::log::attribute_name name = strm.str();
+
+ std::pair< boost::log::attribute_set::iterator, bool > res = set.insert(name, boost::log::attributes::make_constant(5));
+ ++i;
+
+ BOOST_CHECK(res.second); // check that insertion succeeded
+ // check that lookup works
+ boost::log::attribute_set::iterator find_result = set.find(name);
+ BOOST_CHECK(find_result != set.end());
+ BOOST_CHECK(find_result == res.first);
+ }
+
+ boost::log::attribute_value_set vset(set, dummy, dummy);
+ BOOST_CHECK_EQUAL(vset.size(), set.size());
+
+ // Check that all inserted elements are findable
+ unsigned int j = 0;
+ for (boost::log::attribute_value_set::const_iterator it = vset.begin(), end = vset.end(); it != end; ++it, ++j)
+ {
+ boost::log::attribute_name key = it->first;
+ BOOST_CHECK(vset.find(key) != vset.end());
+ }
+
+ // Check that vset.size() is valid
+ BOOST_CHECK_EQUAL(j, i);
+}
diff --git a/src/boost/libs/log/test/run/attr_function.cpp b/src/boost/libs/log/test/run/attr_function.cpp
new file mode 100644
index 00000000..014097f7
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_function.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 attr_function.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the function attribute.
+ */
+
+#define BOOST_TEST_MODULE attr_function
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/utility/result_of.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/function.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ string_expected
+ };
+
+ my_dispatcher() : base_type(*this), m_Expected(none_expected), m_Int(0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ std::string m_String;
+ };
+
+ // A test function that returns an attribute value
+ int get_attr_value()
+ {
+ return 10;
+ }
+
+ // A test functional object that returns an attribute value
+ struct attr_value_generator
+ {
+ typedef std::string result_type;
+
+ explicit attr_value_generator(unsigned int& count) : m_CallsCount(count) {}
+ result_type operator() () const
+ {
+ ++m_CallsCount;
+ return "Hello, world!";
+ }
+
+ private:
+ unsigned int& m_CallsCount;
+ };
+
+} // namespace
+
+// The test verifies that the attribute calls the specified functor and returns the value returned by the functor
+BOOST_AUTO_TEST_CASE(calling)
+{
+ unsigned int call_count = 0;
+ my_dispatcher disp;
+
+ logging::attribute attr1 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(&get_attr_value);
+#else
+ attrs::make_function< int >(&get_attr_value);
+#endif
+
+ logging::attribute attr2 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(attr_value_generator(call_count));
+#else
+ attrs::make_function< std::string >(attr_value_generator(call_count));
+#endif
+
+ logging::attribute_value p1(attr1.get_value());
+ logging::attribute_value p2(attr2.get_value());
+ BOOST_CHECK_EQUAL(call_count, 1u);
+ logging::attribute_value p3(attr2.get_value());
+ BOOST_CHECK_EQUAL(call_count, 2u);
+
+ disp.set_expected(10);
+ BOOST_CHECK(p1.dispatch(disp));
+ BOOST_CHECK(p1.dispatch(disp)); // check that the contained value doesn't change over time or upon dispatching
+
+ disp.set_expected("Hello, world!");
+ BOOST_CHECK(p2.dispatch(disp));
+ BOOST_CHECK(p3.dispatch(disp));
+}
diff --git a/src/boost/libs/log/test/run/attr_named_scope.cpp b/src/boost/libs/log/test/run/attr_named_scope.cpp
new file mode 100644
index 00000000..9429a36c
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_named_scope.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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 attr_named_scope.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the named scope attribute.
+ */
+
+#define BOOST_TEST_MODULE attr_named_scope
+
+#include <sstream>
+#include <boost/mpl/vector.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/value_ref.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ template< typename >
+ struct scope_test_data;
+
+ template< >
+ struct scope_test_data< char >
+ {
+ static logging::string_literal scope1() { return logging::str_literal("scope1"); }
+ static logging::string_literal scope2() { return logging::str_literal("scope2"); }
+ static logging::string_literal file() { return logging::str_literal(__FILE__); }
+ };
+
+} // namespace
+
+// The test verifies that the scope macros are defined
+BOOST_AUTO_TEST_CASE(macros)
+{
+#ifdef BOOST_LOG_USE_CHAR
+ BOOST_CHECK(BOOST_IS_DEFINED(BOOST_LOG_NAMED_SCOPE(name)));
+ BOOST_CHECK(BOOST_IS_DEFINED(BOOST_LOG_FUNCTION()));
+#endif // BOOST_LOG_USE_CHAR
+}
+
+// The test checks that scope tracking works correctly
+BOOST_AUTO_TEST_CASE(scope_tracking)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef attrs::named_scope_entry scope;
+ typedef scope_test_data< char > scope_data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(scope_data::scope1(), scope_data::file(), line1);
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 1UL);
+
+ logging::attribute_value val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ logging::value_ref< scopes > sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 1UL);
+
+ scope const& s1 = sc->front();
+ BOOST_CHECK(s1.scope_name == scope_data::scope1());
+ BOOST_CHECK(s1.file_name == scope_data::file());
+ BOOST_CHECK(s1.line == line1);
+
+ // Second scope
+ const unsigned int line2 = __LINE__;
+ scope new_scope(scope_data::scope2(), scope_data::file(), line2);
+ named_scope::push_scope(new_scope);
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 2UL);
+
+ val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 2UL);
+
+ scopes::const_iterator it = sc->begin();
+ scope const& s2 = *(it++);
+ BOOST_CHECK(s2.scope_name == scope_data::scope1());
+ BOOST_CHECK(s2.file_name == scope_data::file());
+ BOOST_CHECK(s2.line == line1);
+
+ scope const& s3 = *(it++);
+ BOOST_CHECK(s3.scope_name == scope_data::scope2());
+ BOOST_CHECK(s3.file_name == scope_data::file());
+ BOOST_CHECK(s3.line == line2);
+
+ BOOST_CHECK(it == sc->end());
+
+ // Second scope goes out
+ named_scope::pop_scope();
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 1UL);
+
+ val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 1UL);
+
+ scope const& s4 = sc->back(); // should be the same as front
+ BOOST_CHECK(s4.scope_name == scope_data::scope1());
+ BOOST_CHECK(s4.file_name == scope_data::file());
+ BOOST_CHECK(s4.line == line1);
+}
+
+// The test checks that detaching from thread works correctly
+BOOST_AUTO_TEST_CASE(detaching_from_thread)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef scope_test_data< char > scope_data;
+
+ named_scope attr;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ logging::attribute_value val1 = attr.get_value();
+ val1.detach_from_thread();
+
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+ logging::attribute_value val2 = attr.get_value();
+ val2.detach_from_thread();
+
+ logging::value_ref< scopes > sc1 = val1.extract< scopes >(), sc2 = val2.extract< scopes >();
+ BOOST_REQUIRE(!!sc1);
+ BOOST_REQUIRE(!!sc2);
+ BOOST_CHECK_EQUAL(sc1->size(), 1UL);
+ BOOST_CHECK_EQUAL(sc2->size(), 2UL);
+}
+
+// The test checks that output streaming is possible
+BOOST_AUTO_TEST_CASE(ostreaming)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef scope_test_data< char > scope_data;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+
+ std::basic_ostringstream< char > strm;
+ strm << named_scope::get_scopes();
+
+ BOOST_CHECK(!strm.str().empty());
+}
+
+// The test checks that the scope list becomes thread-independent after copying
+BOOST_AUTO_TEST_CASE(copying)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef scope_test_data< char > scope_data;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ scopes sc = named_scope::get_scopes();
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+ BOOST_CHECK_EQUAL(sc.size(), 1UL);
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 2UL);
+}
diff --git a/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp b/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp
new file mode 100644
index 00000000..46fc6a1c
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 attr_sets_insertion_lookup.cpp
+ * \author Andrey Semashev
+ * \date 21.06.2014
+ *
+ * \brief This header contains tests for the attribute and attribute value sets. This test performs special checks
+ * for insert() and find() methods that depend on the attribute name ids and the order in which
+ * insert() operations are invoked, see https://sourceforge.net/p/boost-log/discussion/710022/thread/e883db9a/.
+ */
+
+#define BOOST_TEST_MODULE attr_sets_insertion_lookup
+
+#include <string>
+#include <sstream>
+#include <boost/config.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+template< typename SetT, typename ValueT >
+void test_insertion_lookup(SetT& values, ValueT const& value)
+{
+ // Initialize attribute names. Each name will gain a consecutive id.
+ logging::attribute_name names[20];
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(*names); ++i)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ names[i] = logging::attribute_name(strm.str());
+ }
+
+ // Insert attribute values in this exact order so that different cases in the hash table implementation are tested.
+ values.insert(names[17], value);
+ values.insert(names[1], value);
+ values.insert(names[8], value);
+ values.insert(names[9], value);
+ values.insert(names[10], value);
+ values.insert(names[16], value);
+ values.insert(names[0], value);
+ values.insert(names[11], value);
+ values.insert(names[12], value);
+ values.insert(names[13], value);
+ values.insert(names[14], value);
+ values.insert(names[15], value);
+ values.insert(names[18], value);
+ values.insert(names[19], value);
+ values.insert(names[4], value);
+ values.insert(names[5], value);
+ values.insert(names[7], value);
+ values.insert(names[6], value);
+ values.insert(names[2], value);
+ values.insert(names[3], value);
+
+ // Check that all values are accessible through iteration and find()
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(*names); ++i)
+ {
+ BOOST_CHECK_MESSAGE(values.find(names[i]) != values.end(), "Attribute " << names[i] << " (id: " << names[i].id() << ") not found by find()");
+
+ bool found_by_iteration = false;
+ for (typename SetT::const_iterator it = values.begin(), end = values.end(); it != end; ++it)
+ {
+ if (it->first == names[i])
+ {
+ found_by_iteration = true;
+ break;
+ }
+ }
+
+ BOOST_CHECK_MESSAGE(found_by_iteration, "Attribute " << names[i] << " (id: " << names[i].id() << ") not found by iteration");
+ }
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(attributes)
+{
+ logging::attribute_set values;
+ attrs::constant< int > attr(10);
+
+ test_insertion_lookup(values, attr);
+}
+
+BOOST_AUTO_TEST_CASE(attribute_values)
+{
+ logging::attribute_value_set values;
+ attrs::constant< int > attr(10);
+
+ test_insertion_lookup(values, attr.get_value());
+}
diff --git a/src/boost/libs/log/test/run/attr_value_visitation.cpp b/src/boost/libs/log/test/run/attr_value_visitation.cpp
new file mode 100644
index 00000000..f057fb17
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_value_visitation.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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 attr_value_visitation.cpp
+ * \author Andrey Semashev
+ * \date 21.01.2009
+ *
+ * \brief This header contains tests for the attribute value extraction helpers.
+ */
+
+#define BOOST_TEST_MODULE attr_value_visitation
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include "char_definitions.hpp"
+
+namespace mpl = boost::mpl;
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // The receiver functional object that verifies the extracted attribute values
+ struct my_receiver
+ {
+ typedef void result_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_receiver() : m_Expected(none_expected), m_Int(0), m_Double(0.0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+ void operator() (char value)
+ {
+ // This one should not be called
+ BOOST_ERROR("The unexpected operator() has been called");
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks invokers specialized on a single attribute value type
+BOOST_AUTO_TEST_CASE(single_type)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ logging::value_visitor_invoker< int > invoker1;
+ logging::value_visitor_invoker< double > invoker2;
+ logging::value_visitor_invoker< std::string > invoker3;
+ logging::value_visitor_invoker< char > invoker4;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(invoker1(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(invoker2(data::attr2(), values1, recv));
+
+ // This one will not
+ recv.set_expected();
+ BOOST_CHECK(!invoker3(data::attr3(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(invoker3(data::attr3(), values2, recv));
+
+ // This one will find the sought attribute value, but it will have an incorrect type
+ recv.set_expected();
+ BOOST_CHECK(!invoker4(data::attr1(), values1, recv));
+
+ // This one is the same, but there is a value of the requested type in the set
+ BOOST_CHECK(!invoker1(data::attr2(), values1, recv));
+}
+
+
+// The test checks invokers specialized with type lists
+BOOST_AUTO_TEST_CASE(multiple_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef mpl::vector< int, double, std::string, char >::type types;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ logging::value_visitor_invoker< types > invoker;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(invoker(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(invoker(data::attr2(), values1, recv));
+
+ // This one will not
+ recv.set_expected();
+ BOOST_CHECK(!invoker(data::attr3(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(invoker(data::attr3(), values2, recv));
+}
+
+// The test verifies the visit function
+BOOST_AUTO_TEST_CASE(visit_function)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef mpl::vector< int, double, std::string, char >::type types;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(logging::visit< types >(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(logging::visit< double >(data::attr2(), values1, recv));
+
+ // These will not
+ recv.set_expected();
+ BOOST_CHECK(!logging::visit< types >(data::attr3(), values1, recv));
+ BOOST_CHECK(!logging::visit< char >(data::attr1(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(logging::visit< std::string >(data::attr3(), values2, recv));
+}
diff --git a/src/boost/libs/log/test/run/core.cpp b/src/boost/libs/log/test/run/core.cpp
new file mode 100644
index 00000000..69b42647
--- /dev/null
+++ b/src/boost/libs/log/test/run/core.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 core.cpp
+ * \author Andrey Semashev
+ * \date 08.02.2009
+ *
+ * \brief This header contains tests for the logging core.
+ */
+
+#define BOOST_TEST_MODULE core
+
+#include <cstddef>
+#include <map>
+#include <string>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/core/core.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/core/record.hpp>
+#ifndef BOOST_LOG_NO_THREADS
+#include <boost/thread/thread.hpp>
+#endif // BOOST_LOG_NO_THREADS
+#include "char_definitions.hpp"
+#include "test_sink.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace sinks = logging::sinks;
+namespace expr = logging::expressions;
+
+// The test checks that message filtering works
+BOOST_AUTO_TEST_CASE(filtering)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ boost::shared_ptr< core > pCore = core::get();
+ boost::shared_ptr< test_sink > pSink(new test_sink());
+ pCore->add_sink(pSink);
+
+ // No filtering at all
+ {
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+
+ // Core-level filtering
+ {
+ pCore->set_filter(expr::has_attr(data::attr3()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(!rec);
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+ {
+ pCore->set_filter(expr::has_attr(data::attr2()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+
+ // Sink-level filtering
+ {
+ pCore->reset_filter();
+ pSink->set_filter(expr::has_attr(data::attr2()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+ {
+ pSink->set_filter(expr::has_attr(data::attr3()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(!rec);
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ pSink->reset_filter();
+ }
+ // Only one sink of the two accepts the record
+ {
+ pSink->set_filter(expr::has_attr(data::attr2()));
+
+ boost::shared_ptr< test_sink > pSink2(new test_sink());
+ pCore->add_sink(pSink2);
+ pSink2->set_filter(expr::has_attr(data::attr3()));
+
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+
+ BOOST_CHECK_EQUAL(pSink2->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr4()], 0UL);
+ pCore->remove_sink(pSink2);
+ }
+
+ pCore->remove_sink(pSink);
+ pCore->reset_filter();
+}
+
+#ifndef BOOST_LOG_NO_THREADS
+namespace {
+
+ //! A test routine that runs in a separate thread
+ void thread_attributes_test()
+ {
+ typedef test_data< char > data;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef logging::attribute_set attr_set;
+ attrs::constant< short > attr4(255);
+
+ boost::shared_ptr< core > pCore = core::get();
+ pCore->add_thread_attribute(data::attr4(), attr4);
+
+ attr_set set1;
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(rec);
+ if (rec)
+ pCore->push_record(boost::move(rec));
+ }
+
+} // namespace
+#endif // BOOST_LOG_NO_THREADS
+
+// The test checks that global and thread-specific attributes work
+BOOST_AUTO_TEST_CASE(attributes)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ boost::shared_ptr< core > pCore = core::get();
+ boost::shared_ptr< test_sink > pSink(new test_sink());
+ pCore->add_sink(pSink);
+
+ attr_set::iterator itGlobal = pCore->add_global_attribute(data::attr2(), attr2).first;
+ attr_set::iterator itThread = pCore->add_thread_attribute(data::attr3(), attr3).first;
+
+ {
+ attr_set glob = pCore->get_global_attributes();
+ BOOST_CHECK_EQUAL(glob.size(), 1UL);
+ BOOST_CHECK_EQUAL(glob.count(data::attr2()), 1UL);
+
+ attr_set thr = pCore->get_thread_attributes();
+ BOOST_CHECK_EQUAL(thr.size(), 1UL);
+ BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
+ }
+ {
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+#ifndef BOOST_LOG_NO_THREADS
+ {
+ boost::thread th(&thread_attributes_test);
+ th.join();
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 1UL);
+ pSink->clear();
+
+ // Thread-specific attributes must not interfere
+ attr_set thr = pCore->get_thread_attributes();
+ BOOST_CHECK_EQUAL(thr.size(), 1UL);
+ BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
+ }
+#endif // BOOST_LOG_NO_THREADS
+
+ pCore->remove_global_attribute(itGlobal);
+ pCore->remove_thread_attribute(itThread);
+ pCore->remove_sink(pSink);
+}
diff --git a/src/boost/libs/log/test/run/filt_attr.cpp b/src/boost/libs/log/test/run/filt_attr.cpp
new file mode 100644
index 00000000..23790812
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_attr.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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 filt_attr.cpp
+ * \author Andrey Semashev
+ * \date 31.01.2009
+ *
+ * \brief This header contains tests for the \c attr filter.
+ */
+
+#define BOOST_TEST_MODULE filt_attr
+
+#include <memory>
+#include <string>
+#include <algorithm>
+#include <boost/regex.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/phoenix/bind.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/support/regex.hpp>
+#include <boost/log/expressions.hpp>
+#include "char_definitions.hpp"
+
+namespace phoenix = boost::phoenix;
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that general conditions work
+BOOST_AUTO_TEST_CASE(general_conditions)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::attr< int >(data::attr1()) == 10;
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< int >(data::attr1()) < 0;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< float >(data::attr1()).or_throw() > 0;
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = expr::attr< float >(data::attr1()) > 0;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< int >(data::attr4()).or_throw() >= 1;
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = expr::attr< int >(data::attr4()) >= 1;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< int >(data::attr4()) < 1;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< logging::numeric_types >(data::attr2()) > 5;
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< std::string >(data::attr3()) == "Hello, world!";
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< std::string >(data::attr3()) > "AAA";
+ BOOST_CHECK(f(values1));
+}
+
+// The test checks that is_in_range condition works
+BOOST_AUTO_TEST_CASE(in_range_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 20);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 10);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::is_in_range(expr::attr< int >(data::attr1()), 10, 20);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< logging::numeric_types >(data::attr2()), 5, 6);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()), "AAA", "zzz");
+ BOOST_CHECK(f(values1));
+
+ // Check that strings are saved into the filter by value
+ char buf1[128];
+ char buf2[128];
+ std::strcpy(buf1, "AAA");
+ std::strcpy(buf2, "zzz");
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()), buf1, buf2);
+ std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
+ std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
+ BOOST_CHECK(f(values1));
+
+ std::strcpy(buf1, "AAA");
+ std::strcpy(buf2, "zzz");
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()),
+ static_cast< const char* >(buf1), static_cast< const char* >(buf2));
+ std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
+ std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
+ BOOST_CHECK(f(values1));
+}
+
+namespace {
+
+ struct predicate
+ {
+ typedef bool result_type;
+
+ explicit predicate(unsigned int& present_counter, bool& result) :
+ m_PresentCounter(present_counter),
+ m_Result(result)
+ {
+ }
+
+ template< typename T, typename TagT >
+ result_type operator() (logging::value_ref< T, TagT > const& val) const
+ {
+ m_PresentCounter += !val.empty();
+ return m_Result;
+ }
+
+ private:
+ unsigned int& m_PresentCounter;
+ bool& m_Result;
+ };
+
+} // namespace
+
+// The test checks that phoenix::bind interaction works
+BOOST_AUTO_TEST_CASE(bind_support_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ unsigned int present_counter = 0;
+ bool predicate_result = false;
+
+ filter f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr1()));
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 1U);
+
+ predicate_result = true;
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 2U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< logging::numeric_types >(data::attr2()));
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()).or_throw());
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()));
+ BOOST_CHECK_EQUAL(f(values1), true);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()).or_throw());
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()));
+ BOOST_CHECK_EQUAL(f(values1), true);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+}
+
+// The test checks that begins_with condition works
+BOOST_AUTO_TEST_CASE(begins_with_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()), "hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr2()), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr4()), "Hello");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that ends_with condition works
+BOOST_AUTO_TEST_CASE(ends_with_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::ends_with(expr::attr< std::string >(data::attr3()), "world!");
+ BOOST_CHECK(f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()), "World!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr2()), "world!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr4()), "world!");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that contains condition works
+BOOST_AUTO_TEST_CASE(contains_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::contains(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()), "hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "o, w");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr2()), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr4()), "Hello");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that matches condition works
+BOOST_AUTO_TEST_CASE(matches_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ boost::regex rex("hello");
+ filter f = expr::matches(expr::attr< std::string >(data::attr3()), rex);
+ BOOST_CHECK(!f(values1));
+
+ rex = ".*world.*";
+ f = expr::matches(expr::attr< std::string >(data::attr3()).or_throw(), rex);
+ BOOST_CHECK(f(values1));
+
+ rex = ".*";
+ f = expr::matches(expr::attr< std::string >(data::attr2()), rex);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches(expr::attr< std::string >(data::attr4()), rex);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f =
+ expr::attr< int >(data::attr1()) <= 10 ||
+ expr::is_in_range(expr::attr< double >(data::attr2()), 2.2, 7.7);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::attr< int >(data::attr1()) == 10 &&
+ expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_has_attr.cpp b/src/boost/libs/log/test/run/filt_has_attr.cpp
new file mode 100644
index 00000000..01d2d10a
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_has_attr.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 filt_has_attr.cpp
+ * \author Andrey Semashev
+ * \date 31.01.2009
+ *
+ * \brief This header contains tests for the \c has_attr filter.
+ */
+
+#define BOOST_TEST_MODULE filt_has_attr
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that the filter detects the attribute value presence
+BOOST_AUTO_TEST_CASE(presence_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::has_attr(data::attr1());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr(data::attr4());
+ BOOST_CHECK(!f(values1));
+
+ f = expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr< double >(data::attr3());
+ BOOST_CHECK(!f(values1));
+
+ typedef mpl::vector< unsigned int, char, std::string >::type value_types;
+ f = expr::has_attr< value_types >(data::attr3());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr< value_types >(data::attr1());
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::has_attr(data::attr1()) || expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::has_attr(data::attr1()) && expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp b/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp
new file mode 100644
index 00000000..c34fc731
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 filt_matches_boost_regex.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Regex backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_boost_regex
+
+#include <string>
+#include <boost/regex.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/regex.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp b/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp
new file mode 100644
index 00000000..5e3ca044
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 filt_matches_spirit_classic.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Spirit.Classic backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_spirit_classic
+
+#include <boost/log/detail/config.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+#define BOOST_SPIRIT_THREADSAFE 1
+#endif
+
+#include <string>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/spirit_classic.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace spirit = boost::spirit::classic;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), spirit::uint_p >> '.' >> spirit::uint_p >> '.' >> spirit::uint_p >> '.' >> spirit::uint_p);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), *spirit::lower_p);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), spirit::str_p("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), *spirit::anychar_p);
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p)
+ || expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p)
+ && expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >>*spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp b/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp
new file mode 100644
index 00000000..c85ca011
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 filt_matches_spirit_qi.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Spirit.Qi backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_spirit_qi
+
+#include <string>
+#include <boost/spirit/include/qi_core.hpp>
+#include <boost/spirit/include/qi_rule.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/spirit_qi.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace spirit = boost::spirit::qi;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_);
+ BOOST_CHECK(f(values1));
+
+ // Make sure rules also work
+ f = expr::matches< std::string >(data::attr1(), spirit::rule< std::string::const_iterator, void() >(spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), *spirit::lower);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), spirit::lit("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), *spirit::char_);
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit)
+ || expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit)
+ && expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_std_regex.cpp b/src/boost/libs/log/test/run/filt_matches_std_regex.cpp
new file mode 100644
index 00000000..22455175
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_std_regex.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 filt_matches_std_regex.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with \c std::regex backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_std_regex
+
+#include <boost/config.hpp>
+
+#if !defined(BOOST_NO_CXX11_HDR_REGEX)
+
+#include <string>
+#include <regex>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/std_regex.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef std::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef std::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
+
+#else // !defined(BOOST_NO_CXX11_HDR_REGEX)
+
+int main(int, char*[])
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_NO_CXX11_HDR_REGEX)
diff --git a/src/boost/libs/log/test/run/filt_matches_xpressive.cpp b/src/boost/libs/log/test/run/filt_matches_xpressive.cpp
new file mode 100644
index 00000000..44ee0a61
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_xpressive.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 filt_matches_xpressive.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Xpressive backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_xpressive
+
+#include <string>
+#include <boost/xpressive/xpressive_dynamic.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/xpressive.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::xpressive::basic_regex< const char* > regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type::compile("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type::compile("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type::compile(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::xpressive::basic_regex< const char* > regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/form_attr.cpp b/src/boost/libs/log/test/run/form_attr.cpp
new file mode 100644
index 00000000..ef2deab7
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_attr.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 form_attr.cpp
+ * \author Andrey Semashev
+ * \date 01.02.2009
+ *
+ * \brief This header contains tests for the \c attr formatter.
+ */
+
+#define BOOST_TEST_MODULE form_attr
+
+#include <memory>
+#include <string>
+#include <iomanip>
+#include <ostream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ class my_class
+ {
+ int m_Data;
+
+ public:
+ explicit my_class(int data) : m_Data(data) {}
+
+ template< typename CharT, typename TraitsT >
+ friend std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_class const& obj)
+ {
+ strm << "[data: " << obj.m_Data << "]";
+ return strm;
+ }
+ };
+
+} // namespace
+
+// The test checks that default formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(default_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< my_class > attr3(my_class(77));
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various modes of attribute value type specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< int >(data::attr1()) << expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< logging::numeric_types >(data::attr1()) << expr::attr< logging::numeric_types >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Check that custom types as attribute values are also supported
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< my_class >(data::attr3());
+ f(rec, strm1);
+ strm2 << my_class(77);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Check how missing attribute values are handled
+ {
+ string str1;
+ osstream strm1(str1);
+ formatter f = expr::stream
+ << expr::attr< int >(data::attr1())
+ << expr::attr< int >(data::attr4()).or_throw()
+ << expr::attr< double >(data::attr2());
+ BOOST_CHECK_THROW(f(rec, strm1), logging::runtime_error);
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream
+ << expr::attr< int >(data::attr1())
+ << expr::attr< int >(data::attr4())
+ << expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_auto_newline.cpp b/src/boost/libs/log/test/run/form_auto_newline.cpp
new file mode 100644
index 00000000..0ce38e67
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_auto_newline.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright Andrey Semashev 2019.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ */
+/*!
+ * \file form_auto_newline.cpp
+ * \author Andrey Semashev
+ * \date 23.06.2019
+ *
+ * \brief This header contains tests for the auto_newline formatter.
+ */
+
+#define BOOST_TEST_MODULE form_auto_newline
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace expr = logging::expressions;
+
+// Test appending a newline to a non-empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << "Hello" << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test appending a newline to an empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test not appending a newline to a non-empty string which already ends with a newline
+BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << "Hello\n" << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/form_c_decor.cpp b/src/boost/libs/log/test/run/form_c_decor.cpp
new file mode 100644
index 00000000..442a9392
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_c_decor.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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 form_c_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c c_decor and \c c_ascii_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_c_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/c_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* chars() { return "\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return "\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&\\'()*+,-./0123456789:;<=>\\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+
+ static const char* special_chars() { return "\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82"; }
+ static const char* escaped_special_chars() { return "\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* chars() { return L"\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&\\'()*+,-./0123456789:;<=>\\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+
+ static const wchar_t* special_chars() { return L"\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82"; }
+ static const wchar_t* escaped_special_chars()
+ {
+ if (sizeof(wchar_t) == 1)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82";
+ if (sizeof(wchar_t) == 2)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x007f\\x0080\\x0081\\x0082";
+ if (sizeof(wchar_t) == 4)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x0000007f\\x00000080\\x00000081\\x00000082";
+
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x000000000000007f\\x0000000000000080\\x0000000000000081\\x0000000000000082";
+ }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(c_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_c_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(c_ascii_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_c_ascii_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_char_decor.cpp b/src/boost/libs/log/test/run/form_char_decor.cpp
new file mode 100644
index 00000000..7ef45b96
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_char_decor.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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 form_char_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c char_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_char_decor
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/char_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@aBBBDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`123defghijklmnopqrstuvwxyz{|}~"; }
+
+ static std::vector< std::string > patterns()
+ {
+ std::vector< std::string > v;
+ v.push_back("A");
+ v.push_back("B");
+ v.push_back("C");
+ v.push_back("abc");
+ return v;
+ }
+
+ static std::vector< std::string > replacements()
+ {
+ std::vector< std::string > v;
+ v.push_back("a");
+ v.push_back("BBB");
+ v.push_back("");
+ v.push_back("123");
+ return v;
+ }
+
+ static std::vector< std::pair< std::string, std::string > > decorations()
+ {
+ typedef std::pair< std::string, std::string > element;
+ std::vector< element > v;
+ v.push_back(element("A", "a"));
+ v.push_back(element("B", "BBB"));
+ v.push_back(element("C", ""));
+ v.push_back(element("abc", "123"));
+ return v;
+ }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@aBBBDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`123defghijklmnopqrstuvwxyz{|}~"; }
+
+ static std::vector< std::wstring > patterns()
+ {
+ std::vector< std::wstring > v;
+ v.push_back(L"A");
+ v.push_back(L"B");
+ v.push_back(L"C");
+ v.push_back(L"abc");
+ return v;
+ }
+
+ static std::vector< std::wstring > replacements()
+ {
+ std::vector< std::wstring > v;
+ v.push_back(L"a");
+ v.push_back(L"BBB");
+ v.push_back(L"");
+ v.push_back(L"123");
+ return v;
+ }
+
+ static std::vector< std::pair< std::wstring, std::wstring > > decorations()
+ {
+ typedef std::pair< std::wstring, std::wstring > element;
+ std::vector< element > v;
+ v.push_back(element(L"A", L"a"));
+ v.push_back(element(L"B", L"BBB"));
+ v.push_back(element(L"C", L""));
+ v.push_back(element(L"abc", L"123"));
+ return v;
+ }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::char_decor(data::patterns(), data::replacements())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(zip_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::char_decor(data::decorations())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_csv_decor.cpp b/src/boost/libs/log/test/run/form_csv_decor.cpp
new file mode 100644
index 00000000..714a91bb
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_csv_decor.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 form_csv_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c csv_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_csv_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/csv_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !\"\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !\"\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_csv_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_date_time.cpp b/src/boost/libs/log/test/run/form_date_time.cpp
new file mode 100644
index 00000000..28a3b2dd
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_date_time.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 form_date_time.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the date and time formatters.
+ */
+
+#define BOOST_TEST_MODULE form_date_time
+
+#include <memory>
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <ostream>
+#include <algorithm>
+#include <boost/date_time.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/support/date_time.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+namespace keywords = logging::keywords;
+
+typedef boost::posix_time::ptime ptime;
+typedef boost::gregorian::date gdate;
+typedef ptime::time_duration_type duration;
+
+namespace {
+
+ template< typename CharT >
+ struct date_time_formats;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct date_time_formats< char >
+ {
+ typedef logging::basic_string_literal< char > string_literal_type;
+
+ static string_literal_type default_date_format() { return logging::str_literal("%Y-%b-%d"); }
+ static string_literal_type default_time_format() { return logging::str_literal("%H:%M:%S.%f"); }
+ static string_literal_type default_date_time_format() { return logging::str_literal("%Y-%b-%d %H:%M:%S.%f"); }
+ static string_literal_type default_time_duration_format() { return logging::str_literal("%-%H:%M:%S.%f"); }
+
+ static string_literal_type date_format() { return logging::str_literal("%d/%m/%Y"); }
+ static string_literal_type time_format() { return logging::str_literal("%H.%M.%S"); }
+ static string_literal_type date_time_format() { return logging::str_literal("%d/%m/%Y %H.%M.%S"); }
+ static string_literal_type time_duration_format() { return logging::str_literal("%+%H.%M.%S.%f"); }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct date_time_formats< wchar_t >
+ {
+ typedef logging::basic_string_literal< wchar_t > string_literal_type;
+
+ static string_literal_type default_date_format() { return logging::str_literal(L"%Y-%b-%d"); }
+ static string_literal_type default_time_format() { return logging::str_literal(L"%H:%M:%S.%f"); }
+ static string_literal_type default_date_time_format() { return logging::str_literal(L"%Y-%b-%d %H:%M:%S.%f"); }
+ static string_literal_type default_time_duration_format() { return logging::str_literal(L"%-%H:%M:%S.%f"); }
+
+ static string_literal_type date_format() { return logging::str_literal(L"%d/%m/%Y"); }
+ static string_literal_type time_format() { return logging::str_literal(L"%H.%M.%S"); }
+ static string_literal_type date_time_format() { return logging::str_literal(L"%d/%m/%Y %H.%M.%S"); }
+ static string_literal_type time_duration_format() { return logging::str_literal(L"%+%H.%M.%S.%f"); }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that date_time formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(date_time, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::time_facet< ptime, CharT > facet;
+
+ ptime t1(gdate(2009, 2, 7), ptime::time_duration_type(14, 40, 15));
+ attrs::constant< ptime > attr1(t1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< ptime >(data::attr1(), formats::default_date_time_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::default_date_time_format().c_str())));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< ptime >(data::attr1(), formats::date_time_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::date_time_format().c_str())));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that date formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(date, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::date_facet< gdate, CharT > facet;
+
+ gdate d1(2009, 2, 7);
+ attrs::constant< gdate > attr1(d1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< gdate >(data::attr1(), formats::default_date_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::default_date_format().c_str())));
+ strm2 << d1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< gdate >(data::attr1(), formats::date_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::date_format().c_str())));
+ strm2 << d1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that time_duration formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(time_duration, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::time_facet< ptime, CharT > facet;
+
+ duration t1(14, 40, 15);
+ attrs::constant< duration > attr1(t1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< duration >(data::attr1(), formats::default_time_duration_format().c_str());
+ f(rec, strm1);
+ facet* fac = new facet();
+ fac->time_duration_format(formats::default_time_duration_format().c_str());
+ strm2.imbue(std::locale(strm2.getloc(), fac));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< duration >(data::attr1(), formats::time_duration_format().c_str());
+ f(rec, strm1);
+ facet* fac = new facet();
+ fac->time_duration_format(formats::time_duration_format().c_str());
+ strm2.imbue(std::locale(strm2.getloc(), fac));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_format.cpp b/src/boost/libs/log/test/run/form_format.cpp
new file mode 100644
index 00000000..af249690
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_format.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 form_format.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the Boost.Format-style formatting.
+ */
+
+#define BOOST_TEST_MODULE form_format
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ template< typename >
+ struct format_test_data;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct format_test_data< char > :
+ public test_data< char >
+ {
+ static const char* format1() { return "%1%, %2%"; }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct format_test_data< wchar_t > :
+ public test_data< wchar_t >
+ {
+ static const wchar_t* format1() { return L"%1%, %2%"; }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that Boost.Format formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef format_test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::format(data::format1()) % expr::attr< int >(data::attr1()) % expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << ", " << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_if.cpp b/src/boost/libs/log/test/run/form_if.cpp
new file mode 100644
index 00000000..88f44c49
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_if.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 form_if.cpp
+ * \author Andrey Semashev
+ * \date 05.02.2009
+ *
+ * \brief This header contains tests for the \c if_ formatter.
+ */
+
+#define BOOST_TEST_MODULE form_if
+
+#include <string>
+#include <ostream>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that conditional formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(conditional_formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various modes of attribute value type specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr1()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ];
+ f(rec, strm1);
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1;
+ osstream strm1(str1);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr2()))
+ [
+ expr::stream << expr::attr< int >(data::attr2())
+ ];
+ f(rec, strm1);
+ BOOST_CHECK(equal_strings(strm1.str(), string()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr1()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ]
+ .else_
+ [
+ expr::stream << expr::attr< double >(data::attr2())
+ ];
+ f(rec, strm1);
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr2()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ]
+ .else_
+ [
+ expr::stream << expr::attr< double >(data::attr2())
+ ];
+ f(rec, strm1);
+ strm2 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_max_size_decor.cpp b/src/boost/libs/log/test/run/form_max_size_decor.cpp
new file mode 100644
index 00000000..772f2374
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_max_size_decor.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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 form_max_size_decor.cpp
+ * \author Andrey Semashev
+ * \date 09.08.2016
+ *
+ * \brief This header contains tests for the \c max_size_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_max_size_decor
+
+#include <string>
+#include <locale>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/max_size_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/phoenix/operator.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+#define BOOST_UTF8_DECL
+#define BOOST_UTF8_BEGIN_NAMESPACE namespace {
+#define BOOST_UTF8_END_NAMESPACE }
+
+#include <boost/detail/utf8_codecvt_facet.hpp>
+#include <boost/detail/utf8_codecvt_facet.ipp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* overflow_marker() { return ">>>"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* overflow_marker() { return L">>>"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Test output truncation
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor< CharT >(10)[ expr::stream << expr::attr< string >(data::attr1()) << data::some_test_string() << 1234 << data::abc() ];
+ f(rec, strm1);
+ strm2 << string(data::printable_chars(), 10);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test output truncation with a marker
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ 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() ];
+ f(rec, strm1);
+ strm2 << string(data::printable_chars(), 7) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test nested decorators, when the outer decorator enforces the limit that includes the inner decorator
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor(35, data::overflow_marker())[
+ expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
+ ];
+ f(rec, strm1);
+ strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 7) << data::overflow_marker() << string(data::abcdefg0123456789(), 5) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test nested decorators, when the outer decorator enforces the limit that also limits the inner decorator
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor(25, data::overflow_marker())[
+ expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
+ ];
+ f(rec, strm1);
+ strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 5) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+namespace {
+
+const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(character_boundary_maintenance)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< char > string;
+ typedef logging::basic_formatting_ostream< char > osstream;
+ typedef logging::basic_formatter< char > formatter;
+ typedef test_strings< char > data;
+
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ attrs::constant< string > attr1(narrow_chars);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Test that output truncation does not happen in the middle of a multibyte character
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ strm1.imbue(loc);
+ strm2.imbue(loc);
+ formatter f = expr::stream << expr::max_size_decor< char >(7)[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << string(narrow_chars, 6);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test output truncation with a marker, when the marker length would have caused truncation in the middle of a multibyte character
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ strm1.imbue(loc);
+ strm2.imbue(loc);
+ formatter f = expr::stream << expr::max_size_decor(6, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << string(narrow_chars, 2) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_message.cpp b/src/boost/libs/log/test/run/form_message.cpp
new file mode 100644
index 00000000..4fd946bf
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_message.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 form_message.cpp
+ * \author Andrey Semashev
+ * \date 01.02.2009
+ *
+ * \brief This header contains tests for the \c message formatter.
+ */
+
+#define BOOST_TEST_MODULE form_message
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ template< typename CharT >
+ struct message_test_data;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct message_test_data< char > :
+ public test_data< char >
+ {
+ static expr::smessage_type message() { return expr::smessage; }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct message_test_data< wchar_t > :
+ public test_data< wchar_t >
+ {
+ static expr::wmessage_type message() { return expr::wmessage; }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that message formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(message_formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef message_test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::message().get_name()] = attrs::constant< string >(data::some_test_string());
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << data::message();
+ f(rec, strm1);
+ strm2 << data::some_test_string();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_named_scope.cpp b/src/boost/libs/log/test/run/form_named_scope.cpp
new file mode 100644
index 00000000..3b61e36e
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_named_scope.cpp
@@ -0,0 +1,537 @@
+/*
+ * 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 form_named_scope.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the \c named_scope formatter.
+ */
+
+#define BOOST_TEST_MODULE form_named_scope
+
+#include <string>
+#include <boost/config.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+namespace keywords = logging::keywords;
+
+namespace {
+
+ template< typename CharT >
+ struct named_scope_test_data;
+
+ struct named_scope_test_data_base
+ {
+ static logging::string_literal scope1() { return logging::str_literal("scope1"); }
+ static logging::string_literal scope2() { return logging::str_literal("scope2"); }
+
+ static logging::string_literal file() { return logging::str_literal(__FILE__); }
+ static logging::string_literal posix_file() { return logging::str_literal("/home/user/posix_file.cpp"); }
+ static logging::string_literal windows_file1() { return logging::str_literal("C:\\user\\windows_file1.cpp"); }
+ static logging::string_literal windows_file2() { return logging::str_literal("C:/user/windows_file2.cpp"); }
+ };
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct named_scope_test_data< char > :
+ public test_data< char >,
+ public named_scope_test_data_base
+ {
+ static logging::string_literal default_format() { return logging::str_literal("%n"); }
+ static logging::string_literal full_format() { return logging::str_literal("%n (%f:%l)"); }
+ static logging::string_literal short_filename_format() { return logging::str_literal("%n (%F:%l)"); }
+ static logging::string_literal scope_function_name_format() { return logging::str_literal("%c"); }
+ static logging::string_literal function_name_format() { return logging::str_literal("%C"); }
+ static logging::string_literal delimiter1() { return logging::str_literal("|"); }
+ static logging::string_literal incomplete_marker() { return logging::str_literal("<<and more>>"); }
+ static logging::string_literal empty_marker() { return logging::str_literal("[empty]"); }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct named_scope_test_data< wchar_t > :
+ public test_data< wchar_t >,
+ public named_scope_test_data_base
+ {
+ static logging::wstring_literal default_format() { return logging::str_literal(L"%n"); }
+ static logging::wstring_literal full_format() { return logging::str_literal(L"%n (%f:%l)"); }
+ static logging::wstring_literal short_filename_format() { return logging::str_literal(L"%n (%F:%l)"); }
+ static logging::wstring_literal scope_function_name_format() { return logging::str_literal(L"%c"); }
+ static logging::wstring_literal function_name_format() { return logging::str_literal(L"%C"); }
+ static logging::wstring_literal delimiter1() { return logging::str_literal(L"|"); }
+ static logging::wstring_literal incomplete_marker() { return logging::str_literal(L"<<and more>>"); }
+ static logging::wstring_literal empty_marker() { return logging::str_literal(L"[empty]"); }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+ template< typename CharT >
+ inline bool check_formatting(logging::basic_string_literal< CharT > const& format, logging::record_view const& rec, std::basic_string< CharT > const& expected)
+ {
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef named_scope_test_data< CharT > data;
+
+ string str;
+ osstream strm(str);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(), keywords::format = format.c_str());
+ f(rec, strm);
+ return equal_strings(strm.str(), expected);
+ }
+
+} // namespace
+
+// The test checks that named scopes stack formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::file(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::file(), line2);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // Default format
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << "->" << data::scope2();
+ BOOST_CHECK(check_formatting(data::default_format(), rec, strm.str()));
+ }
+ // Full format
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (" << data::file() << ":" << line1 << ")->"
+ << data::scope2() << " (" << data::file() << ":" << line2 << ")";
+ BOOST_CHECK(check_formatting(data::full_format(), rec, strm.str()));
+ }
+ // Different delimiter
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str());
+ f(rec, strm1);
+ strm2 << data::scope1() << "|" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Different direction
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "<-" << data::scope1();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "|" << data::scope1();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Limiting the number of scopes
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "..." << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "...";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "..." << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "...";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::incomplete_marker = data::incomplete_marker().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "<<and more>>" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::incomplete_marker = data::incomplete_marker().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "<<and more>>";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that empty named scopes stack formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(empty_scopes_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::empty_marker = data::empty_marker().c_str());
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "[empty]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::file(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::file(), line2);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << data::scope1() << "->" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_posix, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::posix_file(), line1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // File names without the full path
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (posix_file.cpp:" << line1 << ")";
+ BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str()));
+ }
+}
+
+#if defined(BOOST_WINDOWS)
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_windows, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::windows_file1(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::windows_file2(), line2);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // File names without the full path
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (windows_file1.cpp:" << line1 << ")->"
+ << data::scope2() << " (windows_file2.cpp:" << line2 << ")";
+ BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str()));
+ }
+}
+
+#endif // defined(BOOST_WINDOWS)
+
+namespace {
+
+struct named_scope_test_case
+{
+ logging::string_literal scope_name;
+ const char* function_name;
+ const char* function_name_no_scope;
+};
+
+const named_scope_test_case named_scope_test_cases[] =
+{
+ // Generic signatures
+ { logging::str_literal("int main(int, char *[])"), "main", "main" },
+ { logging::str_literal("namespace_name::type foo()"), "foo", "foo" },
+ { logging::str_literal("namespace_name::type& foo::bar(int[], std::string const&)"), "foo::bar", "bar" },
+ { logging::str_literal("void* namespc::foo<char>::bar()"), "namespc::foo<char>::bar", "bar" },
+ { logging::str_literal("void* namespc::foo<char>::bar<int>(int) const"), "namespc::foo<char>::bar<int>", "bar<int>" },
+
+ // MSVC-specific
+ { logging::str_literal("int __cdecl main(int, char *[])"), "main", "main" },
+ { logging::str_literal("struct namespc::strooct __cdecl foo3(int [])"), "foo3", "foo3" },
+ { logging::str_literal("void (__cdecl *__cdecl foo4(void))(void)"), "foo4", "foo4" }, // function returning pointer to function
+ { logging::str_literal("void (__cdecl *__cdecl foo5(void (__cdecl *)(void)))(void)"), "foo5", "foo5" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member1(void (__cdecl *)(void)))(void)"), "namespc::my_class<int>::member1", "member1" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member2<int>(int))(void)"), "namespc::my_class<int>::member2<int>", "member2<int>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member2<void(__cdecl *)(void)>(void (__cdecl *)(void)))(void)"), "namespc::my_class<int>::member2<void(__cdecl *)(void)>", "member2<void(__cdecl *)(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member3<void __cdecl foo1(void)>(void))(void)"), "namespc::my_class<int>::member3<void __cdecl foo1(void)>", "member3<void __cdecl foo1(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member1(void (__cdecl *)(void)))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member1", "member1" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member2<int>(int))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member2<int>", "member2<int>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member2<void(__cdecl *)(void)>(void (__cdecl *)(void)))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member2<void(__cdecl *)(void)>", "member2<void(__cdecl *)(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member3<void __cdecl foo1(void)>(void))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member3<void __cdecl foo1(void)>", "member3<void __cdecl foo1(void)>" },
+ { logging::str_literal("void (__cdecl namespc::my_class2::* __cdecl namespc::foo6(void (__cdecl *)(void)))(void)"), "namespc::foo6", "foo6" },
+ { logging::str_literal("struct namespc::my_class<void __cdecl(int)> __cdecl namespc::foo7(void)"), "namespc::foo7", "foo7" },
+ { logging::str_literal("void (__cdecl namespc::my_class2::* const (&__cdecl namespc::foo8(void (__cdecl *)(void)))[2])(void)"), "namespc::foo8", "foo8" },
+ { logging::str_literal("__cdecl namespc::my_class2::my_class2(void)"), "namespc::my_class2::my_class2", "my_class2" },
+ { logging::str_literal("__cdecl namespc::my_class2::~my_class2(void)"), "namespc::my_class2::~my_class2", "~my_class2" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator =(const struct namespc::my_class2 &)"), "namespc::my_class2::operator =", "operator =" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator *(void) const"), "namespc::my_class2::operator *", "operator *" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator ()(void)"), "namespc::my_class2::operator ()", "operator ()" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator <(int) const"), "namespc::my_class2::operator <", "operator <" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator >(int) const"), "namespc::my_class2::operator >", "operator >" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator <=(int) const"), "namespc::my_class2::operator <=", "operator <=" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator >=(int) const"), "namespc::my_class2::operator >=", "operator >=" },
+ { logging::str_literal("__cdecl namespc::my_class2::operator bool(void) const"), "namespc::my_class2::operator bool", "operator bool" },
+ // MSVC generates incorrect strings in case of conversion operators to function types. We don't support these.
+// { logging::str_literal("__cdecl namespc::my_class2::operator char (__cdecl *)(double)(__cdecl *(void) const)(double)"), "namespc::my_class2::operator char (__cdecl *)(double)", "operator char (__cdecl *)(double)" },
+// { logging::str_literal("__cdecl namespc::my_class2::operator char (__cdecl namespc::my_class2::* )(double)(__cdecl namespc::my_class2::* (void) const)(double)"), "namespc::my_class2::operator char (__cdecl namespc::my_class2::* )(double)", "operator char (__cdecl namespc::my_class2::* )(double)" },
+ { logging::str_literal("class std::basic_ostream<char,struct std::char_traits<char> > &__cdecl namespc::operator <<<char,struct std::char_traits<char>>(class std::basic_ostream<char,struct std::char_traits<char> > &,const struct namespc::my_class2 &)"), "namespc::operator <<<char,struct std::char_traits<char>>", "operator <<<char,struct std::char_traits<char>>" },
+ { logging::str_literal("class std::basic_istream<char,struct std::char_traits<char> > &__cdecl namespc::operator >><char,struct std::char_traits<char>>(class std::basic_istream<char,struct std::char_traits<char> > &,struct namespc::my_class2 &)"), "namespc::operator >><char,struct std::char_traits<char>>", "operator >><char,struct std::char_traits<char>>" },
+
+ // GCC-specific
+ { logging::str_literal("namespc::strooct foo3(int*)"), "foo3", "foo3" },
+ { logging::str_literal("void (* foo4())()"), "foo4", "foo4" }, // function returning pointer to function
+ { logging::str_literal("void (* foo5(pfun2_t))()"), "foo5", "foo5" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member1(pfun2_t))() [with T = int; pfun1_t = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member1", "member1" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = int; T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = void (*)(); T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member3())() [with void (* Fun)() = foo1; T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member3", "member3" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member1(pfun2_t))() [with T = void (*)(); pfun1_t = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member1", "member1" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = int; T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = void (*)(); T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member3())() [with void (* Fun)() = foo1; T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member3", "member3" },
+ { logging::str_literal("void (namespc::my_class2::* namespc::foo6(pfun2_t))()"), "namespc::foo6", "foo6" },
+ { logging::str_literal("namespc::my_class<void(int)> namespc::foo7()"), "namespc::foo7", "foo7" },
+ { logging::str_literal("void (namespc::my_class2::* const (& namespc::foo8(pfun2_t))[2])()"), "namespc::foo8", "foo8" },
+ { logging::str_literal("namespc::my_class2::my_class2()"), "namespc::my_class2::my_class2", "my_class2" }, // constructor
+ { logging::str_literal("namespc::my_class2::~my_class2()"), "namespc::my_class2::~my_class2", "~my_class2" }, // destructor
+ { logging::str_literal("void namespc::my_class2::operator=(const namespc::my_class2&)"), "namespc::my_class2::operator=", "operator=" },
+ { logging::str_literal("void namespc::my_class2::operator*() const"), "namespc::my_class2::operator*", "operator*" },
+ { logging::str_literal("void namespc::my_class2::operator()()"), "namespc::my_class2::operator()", "operator()" },
+ { logging::str_literal("bool namespc::my_class2::operator<(int) const"), "namespc::my_class2::operator<", "operator<" },
+ { logging::str_literal("bool namespc::my_class2::operator>(int) const"), "namespc::my_class2::operator>", "operator>" },
+ { logging::str_literal("bool namespc::my_class2::operator<=(int) const"), "namespc::my_class2::operator<=", "operator<=" },
+ { logging::str_literal("bool namespc::my_class2::operator>=(int) const"), "namespc::my_class2::operator>=", "operator>=" },
+ { logging::str_literal("namespc::my_class2::operator bool() const"), "namespc::my_class2::operator bool", "operator bool" },
+ { logging::str_literal("namespc::my_class2::operator pfun1_t() const"), "namespc::my_class2::operator pfun1_t", "operator pfun1_t" },
+ { logging::str_literal("std::basic_ostream<_CharT, _Traits>& namespc::operator<<(std::basic_ostream<_CharT, _Traits>&, const namespc::my_class2&) [with CharT = char; TraitsT = std::char_traits<char>]"), "namespc::operator<<", "operator<<" },
+ { logging::str_literal("std::basic_istream<_CharT, _Traits>& namespc::operator>>(std::basic_istream<_CharT, _Traits>&, namespc::my_class2&) [with CharT = char; TraitsT = std::char_traits<char>]"), "namespc::operator>>", "operator>>" },
+
+ // BOOST_CURRENT_FUNCTION fallback value
+ { logging::str_literal("(unknown)"), "(unknown)", "(unknown)" }
+};
+
+} // namespace
+
+// Function name formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_scope_function_name_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ for (unsigned int i = 0; i < sizeof(named_scope_test_cases) / sizeof(*named_scope_test_cases); ++i)
+ {
+ sentry scope1(named_scope_test_cases[i].scope_name, data::file(), line1, attrs::named_scope_entry::function);
+ string str;
+ osstream strm(str);
+ strm << named_scope_test_cases[i].function_name;
+ BOOST_CHECK_MESSAGE(check_formatting(data::scope_function_name_format(), rec, strm.str()), "Scope name: " << named_scope_test_cases[i].scope_name);
+ }
+}
+
+// Function name without scope formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_function_name_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ for (unsigned int i = 0; i < sizeof(named_scope_test_cases) / sizeof(*named_scope_test_cases); ++i)
+ {
+ sentry scope1(named_scope_test_cases[i].scope_name, data::file(), line1, attrs::named_scope_entry::function);
+ string str;
+ osstream strm(str);
+ strm << named_scope_test_cases[i].function_name_no_scope;
+ BOOST_CHECK_MESSAGE(check_formatting(data::function_name_format(), rec, strm.str()), "Scope name: " << named_scope_test_cases[i].scope_name);
+ }
+}
+
+// The test checks that function name formatters do not affect scopes denoted with BOOST_LOG_NAMED_SCOPE
+BOOST_AUTO_TEST_CASE_TEMPLATE(function_name_does_not_affect_non_function_scopes, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ BOOST_LOG_NAMED_SCOPE("void foo()");
+ string str;
+ osstream strm(str);
+ strm << "void foo()";
+ BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str()));
+ BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_to_log_manip.cpp b/src/boost/libs/log/test/run/form_to_log_manip.cpp
new file mode 100644
index 00000000..a7f83d36
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_to_log_manip.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 form_to_log_manip.cpp
+ * \author Andrey Semashev
+ * \date 05.07.2015
+ *
+ * \brief This header contains tests for support for the \c to_log_manip customization point.
+ */
+
+#define BOOST_TEST_MODULE form_to_log_manip
+
+#include <string>
+#include <ostream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/to_log.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+struct my_class
+{
+ int m_Data;
+
+ explicit my_class(int data) : m_Data(data) {}
+};
+
+} // namespace
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_my_class, "MyClass", my_class)
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_string, "String", std::string)
+
+namespace {
+
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >&
+operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, logging::to_log_manip< my_class, tag::a_my_class > const& obj)
+{
+ strm << "a_my_class: [data: " << obj.get().m_Data << "]";
+ return strm;
+}
+
+} // namespace
+
+namespace std {
+
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >&
+operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, logging::to_log_manip< std::string, tag::a_string > const& obj)
+{
+ strm << "a_string: [" << obj.get() << "]";
+ return strm;
+}
+
+} // namespace std
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overrides, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+
+ attrs::constant< my_class > attr1(my_class(77));
+ attrs::constant< std::string > attr2("Hello");
+
+ attr_set set1;
+ set1[a_my_class.get_name()] = attr1;
+ set1[a_string.get_name()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ // Check that out custom operators are called
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << a_my_class << ", " << a_string;
+ f(rec, strm1);
+ strm2 << "a_my_class: [data: " << 77 << "], a_string: [" << "Hello" << "]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_xml_decor.cpp b/src/boost/libs/log/test/run/form_xml_decor.cpp
new file mode 100644
index 00000000..416c9c4e
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_xml_decor.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 form_xml_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c xml_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_xml_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/xml_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_xml_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp b/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp
new file mode 100644
index 00000000..e26f53a8
--- /dev/null
+++ b/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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 sink_text_ipc_mq_backend.cpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 19.10.2015
+ *
+ * \brief The test verifies that \c text_ipc_message_queue_backend works as expected.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE sink_text_ipc_mq_backend
+
+#include <boost/log/sinks/text_ipc_message_queue_backend.hpp>
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/log/utility/open_mode.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include "make_record.hpp"
+#include "char_definitions.hpp"
+
+const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_text_ipc_mq_backend");
+const unsigned int capacity = 512;
+const unsigned int block_size = 1024;
+const char message[] = "Hello, world!";
+
+// The test checks that `text_ipc_message_queue_backend` works.
+BOOST_AUTO_TEST_CASE(text_ipc_message_queue_backend)
+{
+ typedef boost::log::ipc::reliable_message_queue queue_t;
+ typedef boost::log::sinks::text_ipc_message_queue_backend< queue_t > backend_t;
+
+ // Do a remove in case if a previous test failed
+ queue_t::remove(ipc_queue_name);
+
+ backend_t backend;
+ BOOST_CHECK(!backend.is_open());
+
+ backend.message_queue().create(ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(backend.is_open());
+
+ queue_t queue(boost::log::open_mode::open_only, ipc_queue_name);
+ boost::log::record_view rec = make_record_view();
+ backend.consume(rec, message);
+
+ std::string msg;
+ BOOST_CHECK(queue.try_receive(msg));
+ BOOST_CHECK(equal_strings(msg, message));
+}
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/src_record_ostream.cpp b/src/boost/libs/log/test/run/src_record_ostream.cpp
new file mode 100644
index 00000000..dd321f92
--- /dev/null
+++ b/src/boost/libs/log/test/run/src_record_ostream.cpp
@@ -0,0 +1,479 @@
+/*
+ * 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 src_record_ostream.cpp
+ * \author Andrey Semashev
+ * \date 23.08.2015
+ *
+ * \brief This header contains tests for the log record formatting output stream.
+ */
+
+#define BOOST_TEST_MODULE src_record_ostream
+
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+#include <boost/config.hpp>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/string_view.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/sources/record_ostream.hpp>
+#include <boost/log/expressions/message.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace expr = boost::log::expressions;
+
+namespace {
+
+struct unreferencable_data
+{
+ unsigned int m : 2;
+ unsigned int n : 6;
+
+ enum my_enum
+ {
+ one = 1,
+ two = 2
+ };
+
+ // The following static constants don't have definitions, so they can only be used in constant expressions.
+ // Trying to bind a reference to these members will result in linking errors.
+ static const int x = 7;
+ static const my_enum y = one;
+
+ unreferencable_data()
+ {
+ m = 1;
+ n = 5;
+ }
+};
+
+template< typename CharT >
+struct test_impl
+{
+ typedef CharT char_type;
+ typedef test_data< char_type > strings;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ template< typename StringT >
+ static void width_formatting()
+ {
+ // Check that widening works
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Check that the string is not truncated
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+
+ template< typename StringT >
+ static void fill_formatting()
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ template< typename StringT >
+ static void alignment()
+ {
+ // Left alignment
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Right alignment
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template< typename StringT >
+ static void rvalue_stream()
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type(rec) << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC() << std::flush;
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#endif
+
+ static void output_unreferencable_data()
+ {
+ unreferencable_data data;
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type(rec) << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y << std::flush;
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#endif
+ }
+
+ static void formatting_params_restoring()
+ {
+ record_ostream_type strm_fmt;
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ strm_fmt.attach_record(rec);
+ strm_fmt << std::setw(8) << std::setfill(static_cast< char_type >('x')) << std::hex << 15;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+ strm_fmt.detach_from_record();
+
+ ostream_type strm_correct;
+ strm_correct << std::setw(8) << std::setfill(static_cast< char_type >('x')) << std::hex << 15;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Check that the formatting flags are reset for the next record
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ strm_fmt.attach_record(rec);
+ strm_fmt << 15;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+ strm_fmt.detach_from_record();
+
+ ostream_type strm_correct;
+ strm_correct << 15;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+};
+
+} // namespace
+
+// Test support for width formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for filler character setup
+BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for text alignment
+BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE alignment< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >();
+#endif
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+// Test support for rvalue stream objects
+BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >();
+#endif
+}
+#endif
+
+// Test output of data to which a reference cannot be bound
+BOOST_AUTO_TEST_CASE_TEMPLATE(output_unreferencable_data, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::output_unreferencable_data();
+}
+
+// Test that formatting settings are reset for new log records
+BOOST_AUTO_TEST_CASE_TEMPLATE(formatting_params_restoring, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::formatting_params_restoring();
+}
+
+namespace my_namespace {
+
+class A {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*)
+{
+ strm << "B*";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*)
+{
+ strm << "const B*";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace
+
+// Test operator forwarding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ const my_namespace::A a = my_namespace::A(); // const lvalue
+ my_namespace::B b; // lvalue
+ strm_fmt << a << b << my_namespace::C(); // rvalue
+ strm_fmt << my_namespace::eee;
+ strm_fmt << &b << (my_namespace::B const*)&b;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
+
+namespace my_namespace2 {
+
+class A {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+class C {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+class D {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm,
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ D&&
+#else
+ D const&
+#endif
+ )
+{
+ strm << "D";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace2
+
+// Test operator overriding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overriding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ const my_namespace2::A a = my_namespace2::A(); // const lvalue
+ my_namespace2::B b; // lvalue
+ strm_fmt << a << b << my_namespace2::C() << my_namespace2::D(); // rvalue
+ strm_fmt << my_namespace2::eee;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << "ABCDE";
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
+
+// Test that operator<< returns a record_ostream
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_return_type, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ // The test here verifies that the result of << "Hello" is a record_ostream, not std::ostream or logging::formatting_ostream.
+ // The subsequent << A() will only compile if the stream is record_ostream.
+ strm_fmt << "Hello " << my_namespace2::A();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello A";
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp b/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp
new file mode 100644
index 00000000..e64abb1d
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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_dynamic_type_disp.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the dynamic type dispatcher.
+ */
+
+#define BOOST_TEST_MODULE util_dynamic_type_disp
+
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ // A simple attribute value
+ template< typename T >
+ struct my_value
+ {
+ T m_Value;
+
+ explicit my_value(T const& value) : m_Value(value) {}
+
+ // The function passes the contained type into the dispatcher
+ bool dispatch(logging::type_dispatcher& dispatcher)
+ {
+ logging::type_dispatcher::callback< T > callback = dispatcher.get_callback< T >();
+ if (callback)
+ {
+ callback(m_Value);
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ struct my_visitor
+ {
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_visitor() : m_Expected(none_expected), m_Int(0), m_Double(0.0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void on_int(int const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void on_double(double const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void on_string(std::string const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks that general functionality works
+BOOST_AUTO_TEST_CASE(type_dispatch)
+{
+ my_visitor vis;
+ logging::dynamic_type_dispatcher disp;
+
+ // Register type visitors
+ disp.register_type< int >(boost::bind(&my_visitor::on_int, &vis, _1));
+ disp.register_type< double >(boost::bind(&my_visitor::on_double, &vis, _1));
+
+ BOOST_CHECK(disp.registered_types_count() == 2);
+
+ // Right now strings are not supported by the dispatcher
+ my_value< std::string > val1("Hello world!");
+ BOOST_CHECK(!val1.dispatch(disp));
+
+ // And now they are
+ disp.register_type< std::string >(boost::bind(&my_visitor::on_string, &vis, _1));
+ BOOST_CHECK(disp.registered_types_count() == 3);
+
+ vis.set_expected(val1.m_Value);
+ BOOST_CHECK(val1.dispatch(disp));
+
+ my_value< double > val2(1.2);
+ vis.set_expected(val2.m_Value);
+ BOOST_CHECK(val2.dispatch(disp));
+
+ // This one is not supported
+ my_value< float > val3(static_cast< float >(-4.3));
+ vis.set_expected();
+ BOOST_CHECK(!val3.dispatch(disp));
+}
diff --git a/src/boost/libs/log/test/run/util_exception_handler.cpp b/src/boost/libs/log/test/run/util_exception_handler.cpp
new file mode 100644
index 00000000..1bdb5b41
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_exception_handler.cpp
@@ -0,0 +1,361 @@
+/*
+ * 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_exception_handler.cpp
+ * \author Andrey Semashev
+ * \date 13.07.2009
+ *
+ * \brief This header contains tests for the exception handler functional objects.
+ */
+
+#define BOOST_TEST_MODULE util_exception_handler
+
+#include <string>
+#include <typeinfo>
+#include <stdexcept>
+#include <boost/mpl/vector.hpp>
+#include <boost/smart_ptr/scoped_ptr.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/exception_handler.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ struct my_handler1
+ {
+ typedef void result_type;
+
+ std::type_info const*& m_pExceptionType;
+
+ my_handler1(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ };
+
+ struct my_handler2
+ {
+ typedef void result_type;
+ typedef boost::mpl::vector< std::runtime_error, std::exception >::type exception_types;
+
+ std::type_info const*& m_pExceptionType;
+
+ explicit my_handler2(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ };
+
+ struct my_handler1_nothrow
+ {
+ typedef void result_type;
+
+ std::type_info const*& m_pExceptionType;
+
+ my_handler1_nothrow(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ void operator() () const
+ {
+ m_pExceptionType = &typeid(void);
+ }
+ };
+
+ struct my_handler2_nothrow
+ {
+ typedef void result_type;
+ typedef boost::mpl::vector< std::runtime_error, std::exception >::type exception_types;
+
+ std::type_info const*& m_pExceptionType;
+
+ explicit my_handler2_nothrow(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ void operator() () const
+ {
+ m_pExceptionType = &typeid(void);
+ }
+ };
+
+ struct my_exception {};
+
+ struct my_function0
+ {
+ struct impl_base
+ {
+ virtual ~impl_base() {}
+ virtual void invoke() = 0;
+ };
+
+ template< typename T >
+ struct impl : public impl_base
+ {
+ T m_Fun;
+
+ explicit impl(T const& fun) : m_Fun(fun) {}
+ void invoke() { m_Fun(); }
+ };
+
+ private:
+ boost::scoped_ptr< impl_base > m_pImpl;
+
+ public:
+ template< typename T >
+ my_function0& operator= (T const& fun)
+ {
+ m_pImpl.reset(new impl< T >(fun));
+ return *this;
+ }
+
+ void operator() () const
+ {
+ m_pImpl->invoke();
+ }
+ };
+
+} // namespace
+
+// Tests for handler with explicit exception types specification
+BOOST_AUTO_TEST_CASE(explicit_exception_types)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler<
+ std::runtime_error,
+ std::exception
+ >(my_handler1(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_THROW(handler(), my_exception);
+ }
+ BOOST_REQUIRE(pExceptionType == 0);
+
+ // Verify that exception types are checked in the specified order
+ handler = logging::make_exception_handler<
+ std::exception,
+ std::runtime_error
+ >(my_handler1(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+}
+
+// Tests for handler with explicit exception types specification (no-throw version)
+BOOST_AUTO_TEST_CASE(explicit_exception_types_nothrow)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler<
+ std::runtime_error,
+ std::exception
+ >(my_handler1_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_NO_THROW(handler());
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(void));
+ pExceptionType = 0;
+
+ // Verify that exception types are checked in the specified order
+ handler = logging::make_exception_handler<
+ std::exception,
+ std::runtime_error
+ >(my_handler1_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+}
+
+// Tests for handler with self-contained exception types
+BOOST_AUTO_TEST_CASE(self_contained_exception_types)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler(my_handler2(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_THROW(handler(), my_exception);
+ }
+ BOOST_REQUIRE(pExceptionType == 0);
+}
+
+// Tests for handler with self-contained exception types (no-throw version)
+BOOST_AUTO_TEST_CASE(self_contained_exception_types_nothrow)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler(my_handler2_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_NO_THROW(handler());
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(void));
+ pExceptionType = 0;
+}
diff --git a/src/boost/libs/log/test/run/util_formatting_ostream.cpp b/src/boost/libs/log/test/run/util_formatting_ostream.cpp
new file mode 100644
index 00000000..cd73bcd5
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_formatting_ostream.cpp
@@ -0,0 +1,503 @@
+/*
+ * 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_formatting_ostream.cpp
+ * \author Andrey Semashev
+ * \date 26.05.2013
+ *
+ * \brief This header contains tests for the formatting output stream wrapper.
+ */
+
+#define BOOST_TEST_MODULE util_formatting_ostream
+
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+#include <boost/config.hpp>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/string_view.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+#define BOOST_UTF8_DECL
+#define BOOST_UTF8_BEGIN_NAMESPACE namespace {
+#define BOOST_UTF8_END_NAMESPACE }
+
+#include <boost/detail/utf8_codecvt_facet.hpp>
+#include <boost/detail/utf8_codecvt_facet.ipp>
+
+#endif // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+namespace logging = boost::log;
+
+namespace {
+
+struct unreferencable_data
+{
+ unsigned int m : 2;
+ unsigned int n : 6;
+
+ enum my_enum
+ {
+ one = 1,
+ two = 2
+ };
+
+ // The following static constants don't have definitions, so they can only be used in constant expressions.
+ // Trying to bind a reference to these members will result in linking errors.
+ static const int x = 7;
+ static const my_enum y = one;
+
+ unreferencable_data()
+ {
+ m = 1;
+ n = 5;
+ }
+};
+
+template< typename CharT >
+struct test_impl
+{
+ typedef CharT char_type;
+ typedef test_data< char_type > strings;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ template< typename StringT >
+ static void width_formatting()
+ {
+ // Check that widening works
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ // Check that the string is not truncated
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+ }
+
+ template< typename StringT >
+ static void fill_formatting()
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ template< typename StringT >
+ static void alignment()
+ {
+ // Left alignment
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ // Right alignment
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+ }
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template< typename StringT >
+ static void rvalue_stream()
+ {
+ string_type str_fmt;
+ formatting_ostream_type(str_fmt) << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC() << std::flush;
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
+ }
+#endif
+
+ static void output_unreferencable_data()
+ {
+ unreferencable_data data;
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ {
+ string_type str_fmt;
+ formatting_ostream_type(str_fmt) << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y << std::flush;
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
+ }
+#endif
+ }
+};
+
+} // namespace
+
+// Test support for width formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for filler character setup
+BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for text alignment
+BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE alignment< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >();
+#endif
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+// Test support for rvalue stream objects
+BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >();
+#endif
+}
+#endif
+
+// Test output of data to which a reference cannot be bound
+BOOST_AUTO_TEST_CASE_TEMPLATE(output_unreferencable_data, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::output_unreferencable_data();
+}
+
+namespace my_namespace {
+
+class A {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*)
+{
+ strm << "B*";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*)
+{
+ strm << "const B*";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace
+
+// Test operator forwarding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ const my_namespace::A a = my_namespace::A(); // const lvalue
+ my_namespace::B b; // lvalue
+ strm_fmt << a << b << my_namespace::C(); // rvalue
+ strm_fmt << my_namespace::eee;
+ strm_fmt << &b << (my_namespace::B const*)&b;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b;
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+namespace my_namespace2 {
+
+class A {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+class D {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm,
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ D&&
+#else
+ D const&
+#endif
+ )
+{
+ strm << "D";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace2
+
+// Test operator overriding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overriding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ const my_namespace2::A a = my_namespace2::A(); // const lvalue
+ my_namespace2::B b; // lvalue
+ strm_fmt << a << b << my_namespace2::C() << my_namespace2::D(); // rvalue
+ strm_fmt << my_namespace2::eee;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "ABCDE";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+namespace {
+
+const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
+const wchar_t wide_chars[] = { 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, L',', L' ', 0x043c, 0x0438, 0x0440, L'!', 0 };
+
+template< typename StringT >
+void test_narrowing_code_conversion()
+{
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ // Test rvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ strm_fmt << (StringT)wide_chars;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+ // Test lvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ StringT wstr = StringT(wide_chars);
+ strm_fmt << wstr;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+ // Test const lvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ const StringT wstr = StringT(wide_chars);
+ strm_fmt << wstr;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+}
+
+template< typename StringT >
+void test_widening_code_conversion()
+{
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ // Test rvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ strm_fmt << (StringT)narrow_chars;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+ // Test lvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ StringT str = StringT(narrow_chars);
+ strm_fmt << str;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+ // Test const lvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ const StringT str = StringT(narrow_chars);
+ strm_fmt << str;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+}
+
+} // namespace
+
+// Test character code conversion
+BOOST_AUTO_TEST_CASE(character_code_conversion)
+{
+ test_narrowing_code_conversion< const wchar_t* >();
+ test_widening_code_conversion< const char* >();
+ test_narrowing_code_conversion< std::wstring >();
+ test_widening_code_conversion< std::string >();
+ test_narrowing_code_conversion< boost::wstring_view >();
+ test_widening_code_conversion< boost::string_view >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test_narrowing_code_conversion< std::wstring_view >();
+ test_widening_code_conversion< std::string_view >();
+#endif
+}
+
+#endif
diff --git a/src/boost/libs/log/test/run/util_ipc_object_name.cpp b/src/boost/libs/log/test/run/util_ipc_object_name.cpp
new file mode 100644
index 00000000..11e63e85
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_ipc_object_name.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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_ipc_object_name.cpp
+ * \author Andrey Semashev
+ * \date 07.03.2016
+ *
+ * \brief The test verifies that \c ipc::object_name works.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE util_ipc_object_name
+
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <iostream>
+#include <boost/move/utility_core.hpp>
+#include "char_definitions.hpp"
+
+const char test_object_name1[] = "boost_log_test_object_name1";
+const char test_object_name2[] = "boost_log_test_object_name2";
+
+BOOST_AUTO_TEST_CASE(basic_functionality)
+{
+ // Default constructor.
+ {
+ boost::log::ipc::object_name name;
+ BOOST_CHECK(name.empty());
+ BOOST_CHECK(equal_strings(name.c_str(), ""));
+ }
+
+ // Initializing constructor
+ {
+ boost::log::ipc::object_name name(boost::log::ipc::object_name::global, test_object_name1);
+ BOOST_CHECK(!name.empty());
+ }
+
+ // Copy constructor
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2 = name1;
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Move constructor
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ std::string name_str = name1.c_str();
+ boost::log::ipc::object_name name2 = boost::move(name1);
+ BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str()));
+ }
+
+ // Copy assignment
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2;
+ name2 = name1;
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Move assignment
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ std::string name_str = name1.c_str();
+ boost::log::ipc::object_name name2;
+ name2 = boost::move(name1);
+ BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str()));
+ }
+
+ // Output
+ {
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::global, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::user, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::session, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::process_group, test_object_name1) << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(from_native)
+{
+ boost::log::ipc::object_name name = boost::log::ipc::object_name::from_native(test_object_name1);
+ BOOST_CHECK(equal_strings(name.c_str(), test_object_name1));
+}
+
+BOOST_AUTO_TEST_CASE(name_equivalence)
+{
+ // Test that the same names are equal
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Test that different names don't clash
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+
+ // Test that same named in different scopes don't clash
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+}
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp b/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp
new file mode 100644
index 00000000..38865729
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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_ipc_reliable_mq.cpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 19.10.2015
+ *
+ * \brief The test verifies that \c ipc::reliable_message_queue works.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE util_ipc_reliable_mq
+
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include <boost/log/utility/open_mode.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/test/unit_test.hpp>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <stdexcept>
+#include <boost/move/utility_core.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <algorithm>
+#include <boost/ref.hpp>
+#include <boost/atomic/fences.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/chrono/duration.hpp>
+#endif
+#include "char_definitions.hpp"
+
+typedef boost::log::ipc::reliable_message_queue queue_t;
+typedef queue_t::size_type size_type;
+
+const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_ipc_reliable_mq");
+const unsigned int capacity = 512;
+const size_type block_size = 1024;
+const char message1[] = "Hello, world!";
+const char message2[] = "Hello, the brand new world!";
+
+BOOST_AUTO_TEST_CASE(basic_functionality)
+{
+ // Default constructor.
+ {
+ queue_t queue;
+ BOOST_CHECK(!queue.is_open());
+ }
+
+ // Do a remove in case if a previous test failed
+ queue_t::remove(ipc_queue_name);
+
+ // Opening a non-existing queue
+ try
+ {
+ queue_t queue(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_FAIL("Non-existing queue open succeeded, although it shouldn't have");
+ }
+ catch (std::exception&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+
+ // Create constructor and destructor.
+ {
+ queue_t queue(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(equal_strings(queue.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue.is_open());
+ BOOST_CHECK_EQUAL(queue.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue.block_size(), block_size);
+ }
+
+ // Creating a duplicate queue
+ try
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_FAIL("Creating a duplicate queue succeeded, although it shouldn't have");
+ }
+ catch (std::exception&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+
+ // Opening an existing queue
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(queue_a.is_open());
+
+ queue_t queue_b(boost::log::open_mode::open_or_create, ipc_queue_name, capacity * 2u, block_size * 2u); // queue geometry differs from the existing queue
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+
+ queue_t queue_c(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_c.is_open());
+ BOOST_CHECK(equal_strings(queue_c.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_c.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_c.block_size(), block_size);
+ }
+ // Closing a queue
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(queue_a.is_open());
+ queue_a.close();
+ BOOST_CHECK(!queue_a.is_open());
+ // Duplicate close()
+ queue_a.close();
+ BOOST_CHECK(!queue_a.is_open());
+ }
+ // Move constructor.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b(boost::move(queue_a));
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+ // Move assignment operator.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b;
+ queue_b = boost::move(queue_a);
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+ // Member and non-member swaps.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_a.swap(queue_a);
+ BOOST_CHECK(queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_a.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_a.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_a.block_size(), block_size);
+
+ queue_t queue_b;
+ swap(queue_a, queue_b);
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(message_passing)
+{
+ // try_send() and try_receive()
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.try_send(message1, sizeof(message1) - 1u));
+ BOOST_CHECK(!queue_a.try_send(message2, sizeof(message2) - 1u));
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.try_receive(buffer, sizeof(buffer), message_size));
+ BOOST_CHECK_EQUAL(message_size, sizeof(message1) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message1, message_size) == 0);
+ BOOST_CHECK(!queue_b.try_receive(buffer, sizeof(buffer), message_size));
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ std::string msg;
+ BOOST_CHECK(queue_b.try_receive(msg));
+ BOOST_CHECK_EQUAL(msg.size(), sizeof(message2) - 1u);
+ BOOST_CHECK_EQUAL(msg, message2);
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ std::vector< unsigned char > buf;
+ BOOST_CHECK(queue_b.try_receive(buf));
+ BOOST_CHECK_EQUAL(buf.size(), sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(&buf[0], message2, buf.size()) == 0);
+ }
+
+ // send() and receive() without blocking
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.receive(buffer, sizeof(buffer), message_size) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(message_size, sizeof(message1) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message1, message_size) == 0);
+
+ BOOST_CHECK(queue_a.send(message2, sizeof(message2) - 1u) == queue_t::succeeded);
+ std::string msg;
+ BOOST_CHECK(queue_b.receive(msg) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(msg.size(), sizeof(message2) - 1u);
+ BOOST_CHECK_EQUAL(msg, message2);
+
+ BOOST_CHECK(queue_a.send(message2, sizeof(message2) - 1u) == queue_t::succeeded);
+ std::vector< unsigned char > buf;
+ BOOST_CHECK(queue_b.receive(buf) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(buf.size(), sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(&buf[0], message2, buf.size()) == 0);
+ }
+
+ // send() with an error code on overflow
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size, queue_t::fail_on_overflow);
+ BOOST_TEST_PASSPOINT();
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ BOOST_TEST_PASSPOINT();
+
+ queue_t::operation_result res = queue_a.send(message1, sizeof(message1) - 1u);
+ BOOST_CHECK_EQUAL(res, queue_t::no_space);
+ }
+
+ // send() with an exception on overflow
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size, queue_t::throw_on_overflow);
+ BOOST_TEST_PASSPOINT();
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ BOOST_TEST_PASSPOINT();
+ try
+ {
+ queue_a.send(message1, sizeof(message1) - 1u);
+ BOOST_FAIL("Owerflowing the queue succeeded, although it shouldn't have");
+ }
+ catch (boost::log::capacity_limit_reached&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+ }
+
+ // send() and receive() for messages larger than block_size. The message size and queue capacity below are such
+ // that the last enqueued message is expected to be split in the queue storage.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 5u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+
+ const size_type message_size = block_size * 3u / 2u;
+ std::vector< unsigned char > send_data;
+ send_data.resize(message_size);
+ for (unsigned int i = 0; i < message_size; ++i)
+ send_data[i] = static_cast< unsigned char >(i & 0xFF);
+
+ BOOST_CHECK(queue_a.send(&send_data[0], static_cast< size_type >(send_data.size())) == queue_t::succeeded);
+
+ for (unsigned int i = 0; i < 3; ++i)
+ {
+ BOOST_CHECK(queue_a.send(&send_data[0], static_cast< size_type >(send_data.size())) == queue_t::succeeded);
+
+ std::vector< unsigned char > receive_data;
+ BOOST_CHECK(queue_b.receive(receive_data) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL_COLLECTIONS(send_data.begin(), send_data.end(), receive_data.begin(), receive_data.end());
+ }
+
+ std::vector< unsigned char > receive_data;
+ BOOST_CHECK(queue_b.receive(receive_data) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL_COLLECTIONS(send_data.begin(), send_data.end(), receive_data.begin(), receive_data.end());
+ }
+
+ // clear()
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.try_send(message1, sizeof(message1) - 1u));
+ BOOST_CHECK(!queue_a.try_send(message2, sizeof(message2) - 1u));
+
+ queue_a.clear();
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.try_receive(buffer, sizeof(buffer), message_size));
+ BOOST_CHECK_EQUAL(message_size, sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message2, message_size) == 0);
+ }
+}
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+namespace {
+
+const unsigned int message_count = 100000;
+
+void multithreaded_message_passing_feeding_thread(const char* message, unsigned int& failure_count)
+{
+ const size_type len = static_cast< size_type >(std::strlen(message));
+ queue_t queue(boost::log::open_mode::open_or_create, ipc_queue_name, capacity, block_size);
+ for (unsigned int i = 0; i < message_count; ++i)
+ {
+ failure_count += queue.send(message, len) != queue_t::succeeded;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(multithreaded_message_passing)
+{
+ unsigned int failure_count1 = 0, failure_count2 = 0, failure_count3 = 0;
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ boost::thread thread1(&multithreaded_message_passing_feeding_thread, "Thread 1", boost::ref(failure_count1));
+ boost::thread thread2(&multithreaded_message_passing_feeding_thread, "Thread 2", boost::ref(failure_count2));
+ boost::thread thread3(&multithreaded_message_passing_feeding_thread, "Thread 3", boost::ref(failure_count3));
+
+ BOOST_TEST_PASSPOINT();
+
+ queue_t queue(boost::log::open_mode::open_or_create, ipc_queue_name, capacity, block_size);
+ unsigned int receive_failures = 0, receive_corruptions = 0;
+ unsigned int message_count1 = 0, message_count2 = 0, message_count3 = 0;
+ std::string msg;
+
+ BOOST_TEST_PASSPOINT();
+
+ for (unsigned int i = 0; i < message_count * 3u; ++i)
+ {
+ msg.clear();
+ if (queue.receive(msg) == queue_t::succeeded)
+ {
+ if (msg == "Thread 1")
+ ++message_count1;
+ else if (msg == "Thread 2")
+ ++message_count2;
+ else if (msg == "Thread 3")
+ ++message_count3;
+ else
+ ++receive_corruptions;
+ }
+ else
+ ++receive_failures;
+ }
+
+ BOOST_TEST_PASSPOINT();
+ thread1.join();
+
+ BOOST_TEST_PASSPOINT();
+ thread2.join();
+
+ BOOST_TEST_PASSPOINT();
+ thread3.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(failure_count1, 0u);
+ BOOST_CHECK_EQUAL(message_count1, message_count);
+ BOOST_CHECK_EQUAL(failure_count2, 0u);
+ BOOST_CHECK_EQUAL(message_count2, message_count);
+ BOOST_CHECK_EQUAL(failure_count3, 0u);
+ BOOST_CHECK_EQUAL(message_count3, message_count);
+ BOOST_CHECK_EQUAL(receive_failures, 0u);
+ BOOST_CHECK_EQUAL(receive_corruptions, 0u);
+}
+
+namespace {
+
+void stop_reset_feeding_thread(queue_t& queue, queue_t::operation_result* results, unsigned int count)
+{
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ results[i] = queue.send(message1, sizeof(message1) - 1u);
+ if (results[i] != queue_t::succeeded)
+ break;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+void stop_reset_reading_thread(queue_t& queue, queue_t::operation_result* results, unsigned int count)
+{
+ std::string msg;
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ msg.clear();
+ results[i] = queue.receive(msg);
+ if (results[i] != queue_t::succeeded)
+ break;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(stop_reset_local)
+{
+ queue_t feeder_queue(boost::log::open_mode::open_or_create, ipc_queue_name, 1u, block_size);
+ queue_t::operation_result feeder_results[3];
+ queue_t reader_queue(boost::log::open_mode::open_only, ipc_queue_name);
+ queue_t::operation_result reader_results[3];
+
+ std::fill_n(feeder_results, sizeof(feeder_results) / sizeof(*feeder_results), queue_t::succeeded);
+ std::fill_n(reader_results, sizeof(reader_results) / sizeof(*reader_results), queue_t::succeeded);
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ BOOST_TEST_PASSPOINT();
+
+ // Case 1: Let the feeder block and then we unblock it with stop_local()
+ boost::thread feeder_thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 3);
+ boost::thread reader_thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 1);
+
+ BOOST_TEST_PASSPOINT();
+
+ reader_thread.join();
+ BOOST_TEST_PASSPOINT();
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
+
+ BOOST_TEST_PASSPOINT();
+
+ feeder_queue.stop_local();
+ BOOST_TEST_PASSPOINT();
+ feeder_thread.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(feeder_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[1], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[2], queue_t::aborted);
+ BOOST_CHECK_EQUAL(reader_results[0], queue_t::succeeded);
+
+ // Reset the aborted queue
+ feeder_queue.reset_local();
+ feeder_queue.clear();
+
+ std::fill_n(feeder_results, sizeof(feeder_results) / sizeof(*feeder_results), queue_t::succeeded);
+ std::fill_n(reader_results, sizeof(reader_results) / sizeof(*reader_results), queue_t::succeeded);
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ BOOST_TEST_PASSPOINT();
+
+ // Case 2: Let the reader block and then we unblock it with stop_local()
+ boost::thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 1).swap(feeder_thread);
+ boost::thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 2).swap(reader_thread);
+
+ BOOST_TEST_PASSPOINT();
+
+ feeder_thread.join();
+ BOOST_TEST_PASSPOINT();
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
+
+ BOOST_TEST_PASSPOINT();
+
+ reader_queue.stop_local();
+ BOOST_TEST_PASSPOINT();
+ reader_thread.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(feeder_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[1], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(reader_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(reader_results[1], queue_t::aborted);
+}
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/util_manip_add_value.cpp b/src/boost/libs/log/test/run/util_manip_add_value.cpp
new file mode 100644
index 00000000..9b2227e5
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_add_value.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 <iomanip>
+#include <iostream>
+#include <boost/move/core.hpp>
+#include <boost/io/ios_state.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/sources/record_ostream.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/expressions/keyword.hpp>
+#include <boost/log/utility/manipulators/add_value.hpp>
+#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));
+}
diff --git a/src/boost/libs/log/test/run/util_manip_auto_newline.cpp b/src/boost/libs/log/test/run/util_manip_auto_newline.cpp
new file mode 100644
index 00000000..91f1d07b
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_auto_newline.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright Andrey Semashev 2019.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ */
+/*!
+ * \file util_manip_auto_newline.cpp
+ * \author Andrey Semashev
+ * \date 23.06.2019
+ *
+ * \brief This header contains tests for the auto_newline manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_auto_newline
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/manipulators/auto_newline.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+// Test appending a newline to a non-empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << "Hello" << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test appending a newline to an empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test not appending a newline to a non-empty string which already ends with a newline
+BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << "Hello\n" << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/util_manip_dump.cpp b/src/boost/libs/log/test/run/util_manip_dump.cpp
new file mode 100644
index 00000000..731116cd
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_dump.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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_dump.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the dump manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_dump
+
+#include <vector>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+// Test a short data region
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_lowercase_short_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6e 78 c8 d2 dc";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test a short data region with uppercase formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_uppercase_short_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << std::uppercase << logging::dump(&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6E 78 C8 D2 DC";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test void pointer handling
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_pvoid_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump((void*)&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6e 78 c8 d2 dc";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test a large data region
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_large_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ for (unsigned int i = 0; i < 1024; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test SIMD tail handling
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_tail_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ // 1023 makes it very unlikely for the buffer to end at 16 or 32 byte boundary, which makes the dump algorithm to process the tail in a special way
+ for (unsigned int i = 0; i < 1023; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test bounded dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(bounded_binary_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ for (unsigned int i = 0; i < 1024; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+
+ if (i < 500)
+ {
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+ }
+
+ strm_correct << std::dec << std::setfill(static_cast< char_type >(' ')) << " and " << 524u << " bytes more";
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size(), 500);
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test array dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_element_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned int > data;
+ data.push_back(0x01020a0b);
+ data.push_back(0x03040c0d);
+ data.push_back(0x05060e0f);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump_elements(&data[0], data.size());
+
+ ostream_type strm_correct;
+ const unsigned char* p = reinterpret_cast< const unsigned char* >(&data[0]);
+ std::size_t size = data.size() * sizeof(unsigned int);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ unsigned char n = p[i];
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test bounded array dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(bounded_element_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned int > data;
+ data.push_back(0x01020a0b);
+ data.push_back(0x03040c0d);
+ data.push_back(0x05060e0f);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump_elements(&data[0], data.size(), 2);
+
+ ostream_type strm_correct;
+ const unsigned char* p = reinterpret_cast< const unsigned char* >(&data[0]);
+ std::size_t size = 2 * sizeof(unsigned int);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ unsigned char n = p[i];
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ strm_correct << std::dec << std::setfill(static_cast< char_type >(' ')) << " and " << (data.size() - 2) * sizeof(unsigned int) << " bytes more";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
diff --git a/src/boost/libs/log/test/run/util_manip_to_log.cpp b/src/boost/libs/log/test/run/util_manip_to_log.cpp
new file mode 100644
index 00000000..3937d540
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_to_log.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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_to_log.cpp
+ * \author Andrey Semashev
+ * \date 05.07.2015
+ *
+ * \brief This header contains tests for the \c to_log stream manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_to_log
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/to_log.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+namespace tag {
+
+struct a_my_class;
+
+} // namespace tag
+
+namespace {
+
+struct my_class
+{
+ int m_Data;
+
+ explicit my_class(int data) : m_Data(data) {}
+};
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >&
+operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_class const& obj)
+{
+ strm << "my_class: [data: " << obj.m_Data << "]";
+ return strm;
+}
+
+template< typename StreamT >
+inline StreamT&
+operator<< (StreamT& strm, logging::to_log_manip< my_class > const& obj)
+{
+ strm << "to_log(my_class: [data: " << obj.get().m_Data << "])";
+ return strm;
+}
+
+template< typename StreamT >
+inline StreamT&
+operator<< (StreamT& strm, logging::to_log_manip< my_class, tag::a_my_class > const& obj)
+{
+ strm << "to_log<a_my_class>(my_class: [data: " << obj.get().m_Data << "])";
+ return strm;
+}
+
+template< typename CharT, typename StreamT >
+struct tests
+{
+ typedef CharT char_type;
+ typedef StreamT stream_type;
+ typedef std::basic_string< char_type > string;
+ typedef std::basic_ostringstream< char_type > std_stream;
+
+ //! The test verifies that the default behavior of the manipulator is equivalent to the standard operator<<
+ static void default_operator()
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log(10);
+
+ std_stream strm2;
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ //! The test verifies that operator overrides work
+ static void operator_overrides()
+ {
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << my_class(10);
+
+ std_stream strm2;
+ strm2 << "my_class: [data: " << 10 << "]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log(my_class(10));
+
+ std_stream strm2;
+ strm2 << "to_log(my_class: [data: " << 10 << "])";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log< tag::a_my_class >(my_class(10));
+
+ std_stream strm2;
+ strm2 << "to_log<a_my_class>(my_class: [data: " << 10 << "])";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ }
+};
+
+} // namespace
+
+
+//! The test verifies that the default behavior of the manipulator is equivalent to the standard operator<<
+BOOST_AUTO_TEST_CASE_TEMPLATE(default_operator, CharT, char_types)
+{
+ tests< CharT, std::basic_ostringstream< CharT > >::default_operator();
+ tests< CharT, logging::basic_formatting_ostream< CharT > >::default_operator();
+}
+
+//! The test verifies that operator overrides work
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overrides, CharT, char_types)
+{
+ tests< CharT, std::basic_ostringstream< CharT > >::operator_overrides();
+ tests< CharT, logging::basic_formatting_ostream< CharT > >::operator_overrides();
+}
diff --git a/src/boost/libs/log/test/run/util_once_block.cpp b/src/boost/libs/log/test/run/util_once_block.cpp
new file mode 100644
index 00000000..d952dad7
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_once_block.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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_once_block.cpp
+ * \author Andrey Semashev
+ * \date 24.06.2010
+ *
+ * \brief This header contains tests for once-blocks implementation.
+ *
+ * The test was adopted from test_once.cpp test of Boost.Thread.
+ */
+
+#define BOOST_TEST_MODULE util_once_block
+
+#include <boost/log/utility/once_block.hpp>
+#include <boost/test/unit_test.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+#include <boost/ref.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/barrier.hpp>
+
+namespace logging = boost::log;
+
+enum config
+{
+ THREAD_COUNT = 20,
+ LOOP_COUNT = 100
+};
+
+boost::mutex m;
+typedef boost::lock_guard< boost::mutex > scoped_lock;
+
+logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT;
+int var_to_init_once_flag = 0;
+
+void initialize_variable()
+{
+ // ensure that if multiple threads get in here, they are serialized, so we can see the effect
+ scoped_lock lock(m);
+ ++var_to_init_once_flag;
+}
+
+
+void once_block_flag_thread(boost::barrier& barrier)
+{
+ int my_once_value = 0;
+ barrier.wait();
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK_FLAG(flag)
+ {
+ initialize_variable();
+ }
+
+ my_once_value = var_to_init_once_flag;
+ if (my_once_value != 1)
+ {
+ break;
+ }
+ }
+ scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works
+BOOST_AUTO_TEST_CASE(once_block_flag)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_flag_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch (...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once_flag, 1);
+}
+
+int var_to_init_once = 0;
+
+void once_block_thread(boost::barrier& barrier)
+{
+ int my_once_value = 0;
+ barrier.wait();
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ scoped_lock lock(m);
+ ++var_to_init_once;
+ }
+
+ my_once_value = var_to_init_once;
+ if (my_once_value != 1)
+ {
+ break;
+ }
+ }
+
+ scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK macro works
+BOOST_AUTO_TEST_CASE(once_block)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once, 1);
+}
+
+
+struct my_exception
+{
+};
+
+unsigned int pass_counter = 0;
+unsigned int exception_counter = 0;
+
+void once_block_with_exception_thread(boost::barrier& barrier)
+{
+ barrier.wait();
+ try
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ scoped_lock lock(m);
+ ++pass_counter;
+ if (pass_counter < 3)
+ {
+ throw my_exception();
+ }
+ }
+ }
+ catch (my_exception&)
+ {
+ scoped_lock lock(m);
+ ++exception_counter;
+ }
+}
+
+// The test verifies that the once_block flag is not set if an exception is thrown from the once-block
+BOOST_AUTO_TEST_CASE(once_block_retried_on_exception)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_with_exception_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(pass_counter, 3u);
+ BOOST_CHECK_EQUAL(exception_counter, 2u);
+}
+
+#else // BOOST_LOG_NO_THREADS
+
+namespace logging = boost::log;
+
+enum config
+{
+ LOOP_COUNT = 100
+};
+
+logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT;
+int var_to_init_once_flag = 0;
+
+void initialize_variable()
+{
+ ++var_to_init_once_flag;
+}
+
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works
+BOOST_AUTO_TEST_CASE(once_block_flag)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK_FLAG(flag)
+ {
+ initialize_variable();
+ }
+
+ if (var_to_init_once_flag != 1)
+ {
+ break;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once_flag, 1);
+}
+
+int var_to_init_once = 0;
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK macro works
+BOOST_AUTO_TEST_CASE(once_block)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ ++var_to_init_once;
+ }
+
+ if (var_to_init_once != 1)
+ {
+ break;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once, 1);
+}
+
+struct my_exception
+{
+};
+
+unsigned int pass_counter = 0;
+unsigned int exception_counter = 0;
+
+// The test verifies that the once_block flag is not set if an exception is thrown from the once-block
+BOOST_AUTO_TEST_CASE(once_block_retried_on_exception)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ try
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ ++pass_counter;
+ if (pass_counter < 3)
+ {
+ throw my_exception();
+ }
+ }
+ }
+ catch (my_exception&)
+ {
+ ++exception_counter;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(pass_counter, 3u);
+ BOOST_CHECK_EQUAL(exception_counter, 2u);
+}
+
+#endif // BOOST_LOG_NO_THREADS
diff --git a/src/boost/libs/log/test/run/util_static_type_disp.cpp b/src/boost/libs/log/test/run/util_static_type_disp.cpp
new file mode 100644
index 00000000..3f30ad5d
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_static_type_disp.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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_static_type_disp.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the static type dispatcher.
+ */
+
+#define BOOST_TEST_MODULE util_static_type_disp
+
+#include <string>
+#include <typeinfo>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ // A simple attribute value
+ template< typename T >
+ struct my_value
+ {
+ T m_Value;
+
+ explicit my_value(T const& value) : m_Value(value) {}
+
+ // The function passes the contained type into the dispatcher
+ bool dispatch(logging::type_dispatcher& dispatcher)
+ {
+ logging::type_dispatcher::callback< T > callback = dispatcher.get_callback< T >();
+ if (callback)
+ {
+ callback(m_Value);
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ // The function tests general functionality of the type dispatcher
+ template< typename DispatcherT >
+ void test_general_functionality(DispatcherT& disp)
+ {
+ // These two attributes are supported by the dispatcher
+ my_value< std::string > val1("Hello world!");
+ disp.set_expected(val1.m_Value);
+ BOOST_CHECK(val1.dispatch(disp));
+
+ my_value< double > val2(1.2);
+ disp.set_expected(val2.m_Value);
+ BOOST_CHECK(val2.dispatch(disp));
+
+ // This one is not
+ my_value< float > val3(static_cast< float >(-4.3));
+ disp.set_expected();
+ BOOST_CHECK(!val3.dispatch(disp));
+ }
+
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_dispatcher() :
+ base_type(*this),
+ m_Expected(none_expected),
+ m_Int(0),
+ m_Double(0.0)
+ {
+ }
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks that general functionality works
+BOOST_AUTO_TEST_CASE(type_dispatch)
+{
+ my_dispatcher disp;
+ test_general_functionality(disp);
+}
diff --git a/src/boost/libs/log/test/run/util_stp_filter_parser.cpp b/src/boost/libs/log/test/run/util_stp_filter_parser.cpp
new file mode 100644
index 00000000..946c5f06
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_filter_parser.cpp
@@ -0,0 +1,808 @@
+/*
+ * 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 setup_filter_parser.cpp
+ * \author Andrey Semashev
+ * \date 24.08.2013
+ *
+ * \brief This header contains tests for the filter parser.
+ */
+
+#define BOOST_TEST_MODULE setup_filter_parser
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions/filter.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+typedef logging::attribute_set attr_set;
+typedef logging::attribute_value_set attr_values;
+
+// Tests for attribute presence check
+BOOST_AUTO_TEST_CASE(attr_presence)
+{
+ attrs::constant< int > attr1(10);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr%");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" % MyAttr % ");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+}
+
+// Tests for integer relation filter
+BOOST_AUTO_TEST_CASE(int_relation)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< long > attr2(20);
+ attrs::constant< int > attr3(-2);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyAttr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% != 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < -7");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > -5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% <= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% >= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+}
+
+// Tests for floating point relation filter
+BOOST_AUTO_TEST_CASE(fp_relation)
+{
+ attrs::constant< float > attr1(2.5f);
+ attrs::constant< float > attr2(8.8f);
+ attrs::constant< double > attr3(-9.1);
+ attrs::constant< float > attr4(0.0f);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyAttr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ set1["MyAttr"] = attr4;
+ attr_values values5(set1, set2, set3);
+ values5.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10.3");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% != 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < 5.5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < -7");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 5.6");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > -5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% <= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% >= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+}
+
+// Tests for string relation filter
+BOOST_AUTO_TEST_CASE(string_relation)
+{
+ attrs::constant< std::string > attr1("hello");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyStr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" % MyStr % = \"hello\" ");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \" hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"hello \"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"Hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% != hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% != world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% < world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% > world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+
+ // Check that strings that look like numbers can still be used in filters
+ attrs::constant< std::string > attr2("55");
+ set1["MyStr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"55\"");
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% < \"555\"");
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% > \"44\"");
+ BOOST_CHECK(f(values3));
+ }
+}
+
+// Tests for multiple expression filter
+BOOST_AUTO_TEST_CASE(multi_expression)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< int > attr2(20);
+ attrs::constant< std::string > attr3("hello");
+ attrs::constant< std::string > attr4("world");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyStr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ set1["MyStr"] = attr4;
+ attr_values values5(set1, set2, set3);
+ values5.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 & %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 & %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 and %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 | %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 | %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 or %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 0 & %MyAttr% < 20 | %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+}
+
+// Tests for negation
+BOOST_AUTO_TEST_CASE(negation)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< int > attr2(20);
+ attrs::constant< std::string > attr3("hello");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyStr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ // Test with presence filter
+ {
+ logging::filter f = logging::parse_filter("!%MyAttr%");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" ! % MyAttr % ");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("not %MyAttr%");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("!!%MyAttr%");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+
+ // Test with relations
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 10)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("not ( %MyAttr% = 10 ) ");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% < 20)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+
+ // Test with multiple subexpressions
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 20 & %MyStr% = hello)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 10 | %MyStr% = hello)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+}
+
+// Tests for begins_with relation filter
+BOOST_AUTO_TEST_CASE(begins_with_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"abcd\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"ABCD\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for ends_with relation filter
+BOOST_AUTO_TEST_CASE(ends_with_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"abcd\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"ABCD\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for contains relation filter
+BOOST_AUTO_TEST_CASE(contains_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"abcd\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"ABCD\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"cdAB\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for regex matching relation filter
+BOOST_AUTO_TEST_CASE(matches_relation)
+{
+ attrs::constant< std::string > attr1("hello");
+ attrs::constant< std::string > attr2("127.0.0.1");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ set1["MyIP"] = attr2;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"h.*\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"w.*\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"\\\\d*\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"[a-z]*\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyIP% matches \"\\\\d*\\\\.\\\\d*\\\\.\\\\d*\\\\.\\\\d*\"");
+ BOOST_CHECK(f(values1));
+ }
+}
+
+namespace {
+
+class test_filter_factory :
+ public logging::filter_factory< char >
+{
+private:
+ typedef logging::filter_factory< char > base_type;
+
+public:
+ enum relation_type
+ {
+ custom,
+ exists,
+ equality,
+ inequality,
+ less,
+ greater,
+ less_or_equal,
+ greater_or_equal
+ };
+
+ typedef base_type::string_type string_type;
+
+public:
+ explicit test_filter_factory(logging::attribute_name const& name) : m_name(name), m_rel(custom), m_called(false)
+ {
+ }
+
+ void expect_relation(relation_type rel, string_type const& arg)
+ {
+ m_rel = rel;
+ m_arg = arg;
+ m_custom_rel.clear();
+ }
+
+ void expect_relation(string_type const& rel, string_type const& arg)
+ {
+ m_rel = custom;
+ m_arg = arg;
+ m_custom_rel = rel;
+ }
+
+ void check_called()
+ {
+ BOOST_CHECK(m_called);
+ m_called = false;
+ }
+
+ logging::filter on_exists_test(logging::attribute_name const& name)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, exists);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_equality_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, equality);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_inequality_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, inequality);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_less_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, less);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_greater_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, greater);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_less_or_equal_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, less_or_equal);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_greater_or_equal_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, greater_or_equal);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_custom_relation(logging::attribute_name const& name, string_type const& rel, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, custom);
+ BOOST_CHECK_EQUAL(m_custom_rel, rel);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+
+private:
+ logging::attribute_name m_name;
+ relation_type m_rel;
+ string_type m_arg;
+ string_type m_custom_rel;
+ bool m_called;
+};
+
+} // namespace
+
+// Tests for filter factory
+BOOST_AUTO_TEST_CASE(filter_factory)
+{
+ logging::attribute_name attr_name("MyCustomAttr");
+ boost::shared_ptr< test_filter_factory > factory(new test_filter_factory(attr_name));
+ logging::register_filter_factory(attr_name, factory);
+
+ BOOST_TEST_CHECKPOINT("filter_factory::exists");
+ factory->expect_relation(test_filter_factory::exists, "");
+ logging::parse_filter("%MyCustomAttr%");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "15");
+ logging::parse_filter("%MyCustomAttr% = 15");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello");
+ logging::parse_filter("%MyCustomAttr% = hello");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello");
+ logging::parse_filter("%MyCustomAttr% = \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello\nworld");
+ logging::parse_filter("%MyCustomAttr% = \"hello\\nworld\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::inequality");
+ factory->expect_relation(test_filter_factory::inequality, "hello");
+ logging::parse_filter("%MyCustomAttr% != \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::less");
+ factory->expect_relation(test_filter_factory::less, "hello");
+ logging::parse_filter("%MyCustomAttr% < \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::greater");
+ factory->expect_relation(test_filter_factory::greater, "hello");
+ logging::parse_filter("%MyCustomAttr% > \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::less_or_equal");
+ factory->expect_relation(test_filter_factory::less_or_equal, "hello");
+ logging::parse_filter("%MyCustomAttr% <= \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::greater_or_equal");
+ factory->expect_relation(test_filter_factory::greater_or_equal, "hello");
+ logging::parse_filter("%MyCustomAttr% >= \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::custom");
+ factory->expect_relation("my_relation", "hello");
+ logging::parse_filter("%MyCustomAttr% my_relation \"hello\"");
+ factory->check_called();
+}
+
+// Tests for invalid filters
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% abcd"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("(%MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr%)"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("!"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("!()"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("\"xxx\" == %MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% == \"xxx"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% === \"xxx\""), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% ! \"xxx\""), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% %MyStr2%"), logging::parse_error);
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp b/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp
new file mode 100644
index 00000000..15a60367
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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 setup_formatter_parser.cpp
+ * \author Andrey Semashev
+ * \date 25.08.2013
+ *
+ * \brief This header contains tests for the formatter parser.
+ */
+
+#define BOOST_TEST_MODULE setup_formatter_parser
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+typedef logging::attribute_set attr_set;
+typedef logging::attribute_value_set attr_values;
+typedef logging::record_view record_view;
+
+typedef logging::basic_formatting_ostream< char > osstream;
+typedef logging::basic_formatter< char > formatter;
+
+// Tests for simple attribute placeholders in formatters
+BOOST_AUTO_TEST_CASE(attr_placeholders)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< std::string > attr2("hello");
+ attr_set set1;
+
+ set1["MyAttr"] = attr1;
+ set1["MyStr"] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ formatter f = logging::parse_formatter("String literal");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "String literal";
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: %MyAttr%, MyStr: %MyStr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MyStr: " << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: % MyAttr %, MyStr: % MyStr %");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MyStr: " << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("%MyAttr%%MyStr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << attr1.get() << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: %MyAttr%, MissingAttr: %MissingAttr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MissingAttr: ";
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+}
+
+namespace {
+
+class test_formatter_factory :
+ public logging::formatter_factory< char >
+{
+private:
+ typedef logging::formatter_factory< char > base_type;
+
+public:
+ typedef base_type::string_type string_type;
+ typedef base_type::args_map args_map;
+ typedef base_type::formatter_type formatter_type;
+
+public:
+ explicit test_formatter_factory(logging::attribute_name const& name) : m_name(name), m_called(false)
+ {
+ }
+
+ void expect_args(args_map const& args)
+ {
+ m_args = args;
+ }
+
+ void check_called()
+ {
+ BOOST_CHECK(m_called);
+ m_called = false;
+ }
+
+ formatter_type create_formatter(logging::attribute_name const& name, args_map const& args)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_args.size(), args.size());
+
+ for (args_map::const_iterator it = m_args.begin(), end = m_args.end(); it != end; ++it)
+ {
+ args_map::const_iterator parsed_it = args.find(it->first);
+ if (parsed_it != args.end())
+ {
+ BOOST_TEST_CHECKPOINT(("Arg: " + it->first));
+ BOOST_CHECK_EQUAL(it->second, parsed_it->second);
+ }
+ else
+ {
+ BOOST_ERROR(("Arg not found: " + it->first));
+ }
+ }
+
+ m_called = true;
+ return formatter_type();
+ }
+
+private:
+ logging::attribute_name m_name;
+ args_map m_args;
+ bool m_called;
+};
+
+} // namespace
+
+// Tests for formatter factory
+BOOST_AUTO_TEST_CASE(formatter_factory)
+{
+ logging::attribute_name attr_name("MyCustomAttr");
+ boost::shared_ptr< test_formatter_factory > factory(new test_formatter_factory(attr_name));
+ logging::register_formatter_factory(attr_name, factory);
+
+ {
+ BOOST_TEST_CHECKPOINT("formatter 1");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 2");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr()%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 3");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr ( ) %");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 4");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=10)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 5");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: % MyCustomAttr ( param1 = 10 ) % ");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 6");
+ test_formatter_factory::args_map args;
+ args["param1"] = " 10 ";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=\" 10 \")%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 7");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1 = 10, param2 = abcd)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 8");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=10,param2=abcd)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 9");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ args["param_last"] = "-2.2";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1 = 10, param2 = \"abcd\", param_last = -2.2)%");
+ factory->check_called();
+ }
+}
+
+// Tests for invalid formatters
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(=value)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param,param2)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=value,)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=value,param2)%"), logging::parse_error);
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/test/run/util_stp_settings_parser.cpp b/src/boost/libs/log/test/run/util_stp_settings_parser.cpp
new file mode 100644
index 00000000..1027fb5b
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_settings_parser.cpp
@@ -0,0 +1,294 @@
+/*
+ * 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 setup_settings_parser.cpp
+ * \author Andrey Semashev
+ * \date 25.08.2013
+ *
+ * \brief This header contains tests for the settings parser.
+ */
+
+#define BOOST_TEST_MODULE setup_settings_parser
+
+#include <string>
+#include <sstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/settings_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS)
+
+#include <boost/log/exceptions.hpp>
+
+namespace logging = boost::log;
+
+typedef logging::basic_settings< char > settings;
+
+// Tests for single-level settings
+BOOST_AUTO_TEST_CASE(single_level)
+{
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section2"));
+ BOOST_CHECK(!s.has_section("Section3"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for multi-level settings
+BOOST_AUTO_TEST_CASE(multi_level)
+{
+ {
+ std::istringstream strm
+ (
+ " [Section1]\n"
+ "\n"
+ "Param1 = Value1 \n"
+ "Param2=\"hello, \\\"world\\\"\" \n"
+ "\n"
+ "[Section1.Subsection2] \n"
+ "\n"
+ "Param1=10\n"
+ "Param2=-2.2\n"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section1.Subsection2"));
+ BOOST_CHECK(!s.has_section("Subsection2"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section1.Subsection2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1.Subsection2", "Param2"));
+ BOOST_CHECK(!s.has_parameter("Subsection2", "Param1"));
+ BOOST_CHECK(!s.has_parameter("Subsection2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section1.Subsection2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section1.Subsection2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for comments
+BOOST_AUTO_TEST_CASE(comments)
+{
+ {
+ std::istringstream strm
+ (
+ "# Some comment\n"
+ "[ Section1 ] # another comment\n"
+ "\n"
+ "Param1 = Value1 ### yet another comment \n"
+ "Param2=\"hello, \\\"world\\\"\" # comment after a quoted string\n"
+ "\n"
+ "[ Section2 ]\n"
+ "\n"
+ "Param1=10#comment after a number\n"
+ "Param2=-2.2#comment without a terminating newline"
+ "\n"
+ "#[Section3]\n"
+ "#\n"
+ "#Param1=10#comment after a number\n"
+ "#Param2=-2.2#comment without a terminating newline"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section2"));
+ BOOST_CHECK(!s.has_section("Section3"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for invalid settings
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ {
+ std::istringstream strm
+ (
+ "Param1 = Value1\n" // parameters outside sections
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1\n" // missing closing brace
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "Section1]\n" // missing opening brace
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1=xyz]\n" // invalid characters in the section name
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1# hello?]\n" // invalid characters in the section name
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "(Section1)\n" // invalid braces
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 =\n" // no parameter value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1\n" // no parameter value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\n" // unterminated quote
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1 Value2\n" // multi-word value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS)
diff --git a/src/boost/libs/log/test/run/util_string_literal.cpp b/src/boost/libs/log/test/run/util_string_literal.cpp
new file mode 100644
index 00000000..356f8737
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_string_literal.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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_string_literal.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the string literals wrapper.
+ */
+
+#define BOOST_TEST_MODULE util_string_literal
+
+#include <cwchar>
+#include <cstring>
+#include <set>
+#include <memory>
+#include <string>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/string_literal.hpp>
+
+namespace logging = boost::log;
+
+// Construction tests
+BOOST_AUTO_TEST_CASE(string_literal_ctors)
+{
+ // Default construction
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+ BOOST_CHECK_EQUAL(lit.size(), 0UL);
+ BOOST_CHECK(lit.c_str() != NULL);
+ }
+
+ // Construction from a literal
+ {
+ logging::string_literal lit = "abcd";
+ BOOST_CHECK(!lit.empty());
+ BOOST_CHECK_EQUAL(lit.size(), 4UL);
+ BOOST_CHECK(std::strcmp(lit.c_str(), "abcd") == 0);
+ }
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ // Copying
+ {
+ logging::wstring_literal lit1 = L"Hello";
+ logging::wstring_literal lit2 = lit1;
+ BOOST_CHECK(std::wcscmp(lit2.c_str(), L"Hello") == 0);
+ BOOST_CHECK(std::wcscmp(lit1.c_str(), lit2.c_str()) == 0);
+ }
+
+ // Generator functions
+ {
+ logging::string_literal lit1 = logging::str_literal("Wow!");
+ BOOST_CHECK(std::strcmp(lit1.c_str(), "Wow!") == 0);
+
+ logging::wstring_literal lit2 = logging::str_literal(L"Wow!");
+ BOOST_CHECK(std::wcscmp(lit2.c_str(), L"Wow!") == 0);
+ }
+#endif
+}
+
+// Assignment tests
+BOOST_AUTO_TEST_CASE(string_literal_assignment)
+{
+ // operator=
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+
+ lit = "Hello";
+ BOOST_CHECK(std::strcmp(lit.c_str(), "Hello") == 0);
+
+ logging::string_literal empty_lit;
+ lit = empty_lit;
+ BOOST_CHECK(lit.empty());
+
+ logging::string_literal filled_lit = "Some string";
+ lit = filled_lit;
+ BOOST_CHECK(std::strcmp(lit.c_str(), filled_lit.c_str()) == 0);
+ }
+
+ // assign
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+
+ lit.assign("Hello");
+ BOOST_CHECK(std::strcmp(lit.c_str(), "Hello") == 0);
+
+ logging::string_literal empty_lit;
+ lit.assign(empty_lit);
+ BOOST_CHECK(lit.empty());
+
+ logging::string_literal filled_lit = "Some string";
+ lit.assign(filled_lit);
+ BOOST_CHECK(std::strcmp(lit.c_str(), filled_lit.c_str()) == 0);
+ }
+}
+
+// Comparison tests
+BOOST_AUTO_TEST_CASE(string_literal_comparison)
+{
+ logging::string_literal lit;
+ BOOST_CHECK(lit == "");
+
+ lit = "abcdefg";
+ BOOST_CHECK(lit == "abcdefg");
+ BOOST_CHECK(lit != "xyz");
+ BOOST_CHECK(lit != "aBcDeFg");
+
+ logging::string_literal lit2 = "Yo!";
+ BOOST_CHECK(lit != lit2);
+ lit2 = "abcdefg";
+ BOOST_CHECK(lit == lit2);
+
+ BOOST_CHECK(lit.compare(lit2) == 0);
+ BOOST_CHECK(lit.compare("aaaaa") > 0);
+ BOOST_CHECK(lit.compare("zzzzzzzz") < 0);
+ BOOST_CHECK(lit.compare("zbcdefg") < 0);
+
+ BOOST_CHECK(lit.compare(2, 3, "cde") == 0);
+ BOOST_CHECK(lit.compare(2, 3, "cdefgh", 3) == 0);
+
+ // Check ordering
+ std::set< logging::string_literal > lit_set;
+ lit_set.insert(logging::str_literal("abc"));
+ lit_set.insert(logging::str_literal("def"));
+ lit_set.insert(logging::str_literal("aaa"));
+ lit_set.insert(logging::str_literal("abcd"));
+ lit_set.insert(logging::str_literal("zz"));
+
+ std::set< std::string > str_set;
+ str_set.insert(logging::str_literal("abc").str());
+ str_set.insert(logging::str_literal("def").str());
+ str_set.insert(logging::str_literal("aaa").str());
+ str_set.insert(logging::str_literal("abcd").str());
+ str_set.insert(logging::str_literal("zz").str());
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(lit_set.begin(), lit_set.end(), str_set.begin(), str_set.end());
+}
+
+// Iteration tests
+BOOST_AUTO_TEST_CASE(string_literal_iteration)
+{
+ std::string str;
+ logging::string_literal lit = "abcdefg";
+
+ std::copy(lit.begin(), lit.end(), std::back_inserter(str));
+ BOOST_CHECK(str == "abcdefg");
+
+ str.clear();
+ std::copy(lit.rbegin(), lit.rend(), std::back_inserter(str));
+ BOOST_CHECK(str == "gfedcba");
+}
+
+// Subscript tests
+BOOST_AUTO_TEST_CASE(string_literal_indexing)
+{
+ logging::string_literal lit = "abcdefg";
+
+ BOOST_CHECK_EQUAL(lit[2], 'c');
+ BOOST_CHECK_EQUAL(lit.at(3), 'd');
+
+ BOOST_CHECK_THROW(lit.at(100), std::exception);
+}
+
+// Clearing tests
+BOOST_AUTO_TEST_CASE(string_literal_clear)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ BOOST_CHECK(!lit.empty());
+
+ lit.clear();
+ BOOST_CHECK(lit.empty());
+ BOOST_CHECK_EQUAL(lit, "");
+}
+
+// Swapping tests
+BOOST_AUTO_TEST_CASE(string_literal_swap)
+{
+ logging::string_literal lit1 = "yo-ho-ho";
+ logging::string_literal lit2 = "hello";
+
+ lit1.swap(lit2);
+ BOOST_CHECK_EQUAL(lit1, "hello");
+ BOOST_CHECK_EQUAL(lit2, "yo-ho-ho");
+
+ swap(lit1, lit2);
+ BOOST_CHECK_EQUAL(lit2, "hello");
+ BOOST_CHECK_EQUAL(lit1, "yo-ho-ho");
+}
+
+// STL strings acquisition tests
+BOOST_AUTO_TEST_CASE(string_literal_str)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ std::string str = lit.str();
+ BOOST_CHECK_EQUAL(str, "yo-ho-ho");
+ BOOST_CHECK_EQUAL(lit, str);
+}
+
+// Substring extraction tests
+BOOST_AUTO_TEST_CASE(string_literal_copy)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ char t[32] = { 0 };
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 2), 2UL);
+ BOOST_CHECK(std::strcmp(t, "yo") == 0);
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 4, 2), 4UL);
+ BOOST_CHECK(std::strcmp(t, "-ho-") == 0);
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 100), 8UL);
+ BOOST_CHECK(std::strcmp(t, "yo-ho-ho") == 0);
+}