185 lines
6.7 KiB
Plaintext
185 lines
6.7 KiB
Plaintext
[/
|
|
/ Copyright (c) 2015 Boost.Test contributors
|
|
/
|
|
/ 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)
|
|
/]
|
|
|
|
[section:contexts Contexts]
|
|
|
|
Contexts are a facility provided by the __UTF__ in order to be able to trace the location of assertions better. To grasp
|
|
the idea, consider the following example:
|
|
|
|
|
|
``
|
|
void test_operations(Processor& processor, int limit)
|
|
{
|
|
for (int i = 0; i < limit; ++i) {
|
|
BOOST_TEST(processor.op1(i));
|
|
for (int j = 0; j < i; ++j) {
|
|
BOOST_TEST(processor.op2(i, j));
|
|
}
|
|
}
|
|
}
|
|
``
|
|
|
|
In case of failure, in order to see in the logs at which point of the loops the failure occurred, we need some extra
|
|
information in the assertion, which can be achieved for instance [link boost_test.testing_tools.reports.custom_messages the following way]:
|
|
|
|
|
|
``
|
|
BOOST_TEST(processor.op1(i));
|
|
``
|
|
|
|
replaced by
|
|
|
|
``
|
|
BOOST_TEST(processor.op1(i), "With parameter i = " << i);
|
|
``
|
|
|
|
We see in this trivial example that a context, which is the variable `i` in this case, should be acknowledged by the
|
|
assertion `BOOST_CHECK` in a particular way. In the approach above, this is done by adding a message to the assertion
|
|
itself.
|
|
|
|
What if the context is more complex than that? In case the complexity of the context increases, the fact that the
|
|
assertion and the context is tightly coupled as in the approach above is difficult to maintain:
|
|
|
|
``
|
|
void test_operations(Processor& processor, int limit, int level)
|
|
{
|
|
for (int i = 0; i < limit; ++i) {
|
|
BOOST_TEST(processor.op1(i),
|
|
"With optimization level " << level << ", With parameter i = " << i);
|
|
for (int j = 0; j < i; ++j) {
|
|
BOOST_TEST(processor.op2(i, j),
|
|
"With optimization level " << level <<
|
|
", With parameter i = " << i << ", With parameter j = " << j);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test1)
|
|
{
|
|
Processor processor;
|
|
|
|
for (int level = 0; level < 3; ++level) {
|
|
processor.optimization_level(level);
|
|
test_operations(processor, 2, level);
|
|
}
|
|
}
|
|
``
|
|
|
|
Note the length of the messages, the repetition, and the fact, that we pass argument `level` to function
|
|
`test_operations` only for the sake of generating an error message in case of a failure.
|
|
|
|
Therefore, *loose* coupling between the context of an assertion and the assertion point is a property that is desirable.
|
|
|
|
[#ref_BOOST_TEST_INFO][h3 Assertion-bound context]
|
|
|
|
`BOOST_TEST_INFO` can be used to define an error message to be bound to the first following assertion. If (and only
|
|
if) the assertion fails, the bound message will be displayed along:
|
|
|
|
[bt_example example80_contexts..Assertion-bound context..run-fail]
|
|
|
|
The information composed inside `BOOST_TEST_INFO` is bound only to the first assertion
|
|
following the declaration. This information is only displayed if the assertion fails; otherwise the message is
|
|
discarded. The `BOOST_TEST_INFO` declaration does not have to immediately precede the assertion, it is allowed to
|
|
intertwine them with other instructions, they can even be declared in different scopes. It is also possible to
|
|
bind more than one information to a given assertion.
|
|
|
|
With `BOOST_TEST_INFO`, we can improve our initial example as follows:
|
|
|
|
|
|
``
|
|
void test_operations(Processor& processor, int limit, int level)
|
|
{
|
|
for (int i = 0; i < limit; ++i) {
|
|
BOOST_TEST_INFO("With optimization level " << level);
|
|
BOOST_TEST_INFO("With parameter i = " << i);
|
|
BOOST_TEST(processor.op1(i));
|
|
for (int j = 0; j < i; ++j) {
|
|
BOOST_TEST_INFO("With optimization level " << level);
|
|
BOOST_TEST_INFO("With parameter i = " << i);
|
|
BOOST_TEST_INFO("With parameter j = " << j);
|
|
BOOST_TEST(processor.op2(i, j));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test1)
|
|
{
|
|
Processor processor;
|
|
|
|
for (int level = 0; level < 3; ++level) {
|
|
processor.optimization_level(level);
|
|
test_operations(processor, 2, level);
|
|
}
|
|
}
|
|
``
|
|
|
|
[#ref_BOOST_TEST_CONTEXT][h3 Scope-bound context]
|
|
|
|
In the previous example, the information stored inside the calls to `BOOST_TEST_INFO` were all consumed by the next assertion. There are cases
|
|
where we would like this information be persistent for the current scope. __UTF__ provides two tools to achieve this:
|
|
|
|
* `BOOST_TEST_CONTEXT` defines a diagnostic message and a scope. The message is bound to every assertion in that scope,
|
|
and is displayed along with every failed assertion.
|
|
* `BOOST_TEST_INFO_SCOPE` acts the same as `BOOST_TEST_INFO`, but the stored context information is bound to all the assertions
|
|
that follow the call to `BOOST_TEST_INFO_SCOPE` within the current scope.
|
|
|
|
[tip Since Boost [link ref_CHANGE_LOG_3_10 Boost 1.70], `BOOST_TEST_CONTEXT` can accept multiple arguments.]
|
|
[tip `BOOST_TEST_INFO_SCOPE` has been introduced in [link ref_CHANGE_LOG_3_10 Boost 1.70].]
|
|
|
|
[bt_example example81_contexts..Scope-bound context..run-fail]
|
|
|
|
In the previous example, there is an opening brace right after `BOOST_TEST_CONTEXT`: this pair of braces defines the scope in which
|
|
the diagnostic message is in effect. If there is no braces, the scope applies only to the following statement.
|
|
`BOOST_TEST_CONTEXT` declarations can nest.
|
|
|
|
With `BOOST_TEST_CONTEXT`, we can further improve our initial example, by putting variable `level` into a scope-level context
|
|
and not pass it as function parameter:
|
|
|
|
``
|
|
void test_operations(Processor& processor, int limit)
|
|
{
|
|
for (int i = 0; i < limit; ++i) {
|
|
BOOST_TEST_INFO("With parameter i = " << i);
|
|
BOOST_TEST(processor.op1(i));
|
|
for (int j = 0; j < i; ++j) {
|
|
BOOST_TEST_INFO("With parameter i = " << i);
|
|
BOOST_TEST_INFO("With parameter j = " << j);
|
|
BOOST_TEST(processor.op2(i, j));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test1)
|
|
{
|
|
Processor processor;
|
|
|
|
for (int level = 0; level < 3; ++level) {
|
|
BOOST_TEST_CONTEXT("With optimization level " << level) {
|
|
processor.optimization_level(level);
|
|
test_operations(processor, 2);
|
|
}
|
|
}
|
|
}
|
|
``
|
|
If we observe that variable `i` also applies in a certain scope, we can improve our example further still.
|
|
|
|
[bt_example example82_contexts..Using contexts..run-fail]
|
|
|
|
Finally, it is possible to pass several arguments to `BOOST_TEST_CONTEXT`, which is more convenient than having
|
|
several scopes:
|
|
|
|
[bt_example example83_contexts..Multiple arguments to `BOOST_TEST_CONTEXT`..run-fail]
|
|
|
|
`BOOST_TEST_INFO_SCOPE` is convenient when you augment the current scope information as new information arrives.
|
|
The following example calls several time a quadratic polynomial estimation function with random polynomial. As the
|
|
random values are drawn in a loop, they are placed in the current scope with `BOOST_TEST_INFO_SCOPE`, which allows us
|
|
to easily debug the function.
|
|
|
|
[bt_example example84_contexts..Sticky context with `BOOST_TEST_INFO_SCOPE`..run-fail]
|
|
|
|
[endsect] [/ contexts ]
|