log/test/run/attr_named_scope.cpp
2015-01-25 17:32:33 +03:00

191 lines
5.9 KiB
C++

/*
* 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);
}