diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/log/test | |
parent | Initial commit. (diff) | |
download | ceph-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')
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 " !"#$%&'()*+,-./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_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); +} |