Skip to content

Commit

Permalink
Merge branch 'topic/12540-printing-types-customisation-point' into ne…
Browse files Browse the repository at this point in the history
…xt-internal

* topic/12540-printing-types-customisation-point:
  Change log update
  Documenting the customization point
  Fixing the tests and checking everything works ok
  Test for customization points
  Customization points for printing user defined types through `boost_test_print_type`
  • Loading branch information
raffienficiaud committed Mar 9, 2017
2 parents 3f6cd34 + 1f803ae commit 7051d36
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 13 deletions.
5 changes: 4 additions & 1 deletion doc/closing_chapters/change_log.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
[h4 Boost.Test v3.5 / boost 1.64]

[h5 New features]
* Now Boost.Test provides [link ref_log_output_custom_customization_point customization points] for logging user defined types:
this solution is less intrusive than forcing the definition of `operator<<` for a specific type.
* [link boost_test.test_output.log_formats.log_junit_format JUnit output format] can now have a
[link boost_test.test_output.log_formats.test_log_output log-level] set between `success` and
`non-fatal error`, and defaults to `general information`.
* [link boost_test.test_output.log_formats.log_junit_format JUnit output format] is now more
performant in case a lot of checks are done in a test module.

[h5 Bugfixes and feature requests]
# [pull_request 107] `BOOST_NO_EXCEPTIONS` typo making `throw_exception` unusable under some circumstances
# [pull_request 107] `BOOST_NO_EXCEPTIONS` typo making `throw_exception` unusable under some circumstances
# [pull_request 108] Change capital variable names to lowercase
# [ticket 12540] Provide customisation point for printing types in tests
# [ticket 12712] `BOOST_AUTO_TEST_SUITE`: Generate unique names by using `__COUNTER__`
# [ticket 12748] Boost.Test defines a variable called `VERSION`
# [ticket 12778] Boost.Test is broken against left shift operator in certain cases (`nullptr` issue)
Expand Down
12 changes: 12 additions & 0 deletions doc/examples/logger-customization-point.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//[example_output
> logger-customization-point --log_level=all
Running 1 test case...
Entering test module "logger-customization-point"
test.cpp(36): Entering test case "test1"
test.cpp(39): error: in "test1": check t == 11 has failed [** value of user_defined_type is 10 ** != 11]
test.cpp(43): info: check t2 == 11 has passed
test.cpp(36): Leaving test case "test1"; testing time: 125us
Leaving test module "logger-example-customization-point"; testing time: 157us

*** 1 failure is detected in the test module "logger-customization-point"
//]
45 changes: 45 additions & 0 deletions doc/examples/logger-customization-point.run-fail.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// (C) Copyright Raffi Enficiaud 2017.
// 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)

// See http://www.boost.org/libs/test for the library home page.
//
//! @file
//! Customization point for printing user defined types
// *****************************************************************************

//[example_code
#define BOOST_TEST_MODULE logger-customization-point
#include <boost/test/included/unit_test.hpp>

namespace user_defined_namespace {
struct user_defined_type {
int value;

user_defined_type(int value_) : value(value_)
{}

bool operator==(int right) const {
return right == value;
}
};
}

namespace user_defined_namespace {
std::ostream& boost_test_print_type(std::ostream& ostr, user_defined_type const& right) {
ostr << "** value of user_defined_type is " << right.value << " **";
return ostr;
}
}

BOOST_AUTO_TEST_CASE(test1)
{
user_defined_namespace::user_defined_type t(10);
BOOST_TEST(t == 11);

using namespace user_defined_namespace;
user_defined_type t2(11);
BOOST_TEST(t2 == 11);
}
//]
34 changes: 30 additions & 4 deletions doc/test_output/test_tools_support.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,36 @@ arguments to the output stream in some form of log statement. If arguments type
``
operator<<(std::ostream&, ArgumentType const&);
``
interface you will get a compilation error. You can either implement above interface or prohibit
the [link boost_test.testing_tools testing tools] from logging argument values for
specified type. To do so, use following statement on file level before first test case that
includes statement failing to compile:
interface, you will get a compilation error.

The __UTF__ supports three different methods for logging user defined types:

# through the `operator<<` for that specific type: any type that implements the above interface has direct support for
logging,
# through a customization point responsible for logging a specific type, which is less intrusive than the implementation
of `operator<<`. This is explained in more details in [link ref_log_output_custom_customization_point this section],
# by prohibiting the [link boost_test.testing_tools testing tools] from logging argument values for
specified type through __BOOST_TEST_DONT_PRINT_LOG_VALUE__.
This is explained in more details in [link ref_log_output_custom_avoid_printing this section].

[#ref_log_output_custom_customization_point]
[h4 User type customization point for logging]
It is possible to indicate a function, `boost_test_print_type`, to __UTF__ that is responsible for the printing of a user defined type, without
the need to override the `operator<<` for that specific type. This is convenient for instance when
the `operator<<` has already been defined for other needs.

The syntax follows the `operator<<`, and this function should be in the same namespace as the type:

```
std::ostream& boost_test_print_type(std::ostream& ostr, ArgumentType const& right);
```

[bt_example logger-customization-point..Logging customization point usage..run-fail]

[#ref_log_output_custom_avoid_printing]
[h4 Prohibiting the printing of a specific type]
To prohibit the printing of a specific type, use the following statement on file level before first
test case that includes statement failing to compile:

``
BOOST_TEST_DONT_PRINT_LOG_VALUE(ArgumentType)
Expand Down
6 changes: 6 additions & 0 deletions include/boost/test/impl/test_tools.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ namespace tt_detail {
// ************** print_log_value ************** //
// ************************************************************************** //

void
print_log_value<bool>::operator()( std::ostream& ostr, bool t )
{
ostr << std::boolalpha << t;
}

void
print_log_value<char>::operator()( std::ostream& ostr, char t )
{
Expand Down
43 changes: 35 additions & 8 deletions include/boost/test/tools/detail/print_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,52 @@ namespace boost {
namespace test_tools {
namespace tt_detail {

// ************************************************************************** //
// ************** boost_test_print_type ************** //
// ************************************************************************** //

namespace impl {
template <class T>
std::ostream& boost_test_print_type(std::ostream& ostr, T const& t) {
BOOST_STATIC_ASSERT_MSG( (boost::has_left_shift<std::ostream,T>::value),
"Type has to implement operator<< to be printable");
ostr << t;
return ostr;
}

struct boost_test_print_type_impl {
template <class R>
std::ostream& operator()(std::ostream& ostr, R const& r) const {
return boost_test_print_type(ostr, r);
}
};
}

// To avoid ODR violations, see N4381
template <class T> struct static_const { static const T value; };
template <class T> const T static_const<T>::value = T();

namespace {
static const impl::boost_test_print_type_impl& boost_test_print_type =
static_const<impl::boost_test_print_type_impl>::value;
}


// ************************************************************************** //
// ************** print_log_value ************** //
// ************************************************************************** //

template<typename T>
struct print_log_value {
BOOST_STATIC_ASSERT_MSG( (boost::has_left_shift<std::ostream,T>::value),
"Type has to implement operator<< to be printable");

void operator()( std::ostream& ostr, T const& t )
{
typedef typename mpl::or_<is_array<T>,is_function<T>,is_abstract<T> >::type cant_use_nl;

std::streamsize old_precision = set_precision( ostr, cant_use_nl() );

ostr << t;
//ostr << t;
using boost::test_tools::tt_detail::boost_test_print_type;
boost_test_print_type(ostr, t);

if( old_precision != (std::streamsize)-1 )
ostr.precision( old_precision );
Expand Down Expand Up @@ -103,10 +133,7 @@ struct print_log_value< T[N] > {

template<>
struct BOOST_TEST_DECL print_log_value<bool> {
void operator()( std::ostream& ostr, bool t )
{
ostr << std::boolalpha << t;
}
void operator()( std::ostream& ostr, bool t );
};

//____________________________________________________________________________//
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ test-suite "writing-test-ts"
[ boost.test-self-test run : writing-test-ts : tools-debuggable-test : : : : : : $(requirements_boost_test_full_support) ]
[ boost.test-self-test run : writing-test-ts : test-dataset-over-tuples : : : : : : $(requirements_datasets) ]
[ boost.test-self-test run : writing-test-ts : nullptr-support-test : : : : : : [ requires cxx11_nullptr ] ]
[ boost.test-self-test run : writing-test-ts : user-defined-types-logging-customization-points ]
;

#_________________________________________________________________________________________________#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// (C) Copyright Raffi Enficiaud 2017.
// 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)

// See http://www.boost.org/libs/test for the library home page.
//
//! @file
//! Customization point for printing user defined types
// *****************************************************************************

#define BOOST_TEST_MODULE user type logger customization points
#include <boost/test/unit_test.hpp>

namespace printing_test {
struct user_defined_type {
int value;

user_defined_type(int value_) : value(value_)
{}

bool operator==(int right) const {
return right == value;
}
};

std::ostream& boost_test_print_type(std::ostream& ostr, user_defined_type const& right) {
ostr << "** value of my type is " << right.value << " **";
return ostr;
}
}

//using namespace printing_test;

BOOST_AUTO_TEST_CASE(test1)
{
//using printing_test::user_defined_type;
printing_test::user_defined_type t(10);
BOOST_CHECK_EQUAL(t, 10);
#ifndef BOOST_TEST_MACRO_LIMITED_SUPPORT
BOOST_TEST(t == 10);
#endif
}

0 comments on commit 7051d36

Please sign in to comment.