123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- [/
- / 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 ]
|