|  | Home | Libraries | People | FAQ | More | 
Let's consider the following example:
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_macro3 #include <boost/test/included/unit_test.hpp> BOOST_AUTO_TEST_CASE( test_op_reportings ) { int a = 13, b = 12; BOOST_TEST(a == b); BOOST_TEST(a < b); BOOST_TEST(a - 1 < b); BOOST_TEST(b > a - 1); } | 
| Output | 
|---|
| > ./boost_test_macro3 --log_level=all Running 1 test case... Entering test module "boost_test_macro3" test.cpp(12): Entering test case "test_op_reportings" test.cpp(15): error: in "test_op_reportings": check a == b has failed [13 != 12] test.cpp(16): error: in "test_op_reportings": check a < b has failed [13 >= 12] test.cpp(17): error: in "test_op_reportings": check a - 1 < b has failed [13 - 1 >= 12] test.cpp(18): error: in "test_op_reportings": check b > a - 1 has failed [12 <= 12] test.cpp(12): Leaving test case "test_op_reportings"; testing time: 484us Leaving test module "boost_test_macro3"; testing time: 588us *** 2 failures are detected in the test module "boost_test_macro3" | 
        It was already mentioned that the reporting is not symmetrical (see here). An expression is
        constructed from the statement
        appearing in the BOOST_TEST
        macro. This expression allows evaluation and reporting such as "13 - 1 >= 12" failed
        along with a copy of the statement,
        which contains more details than "a - 1
        < b" failed. In
        details, what happens is the following:
      
            a special object, the seed
            of the expression, is composed from the left side of statement.
            This initial composition has highest precedence over the supported operations.
            The expression below:
          
a op1 b op2 c op3 d
is actually seen as
( seed a ) op1 b op2 c op3 d
            The "seed a"
            returns an expression
            object that keep tracks of the type of a.
            This expression has overloads for left-to-right associativity, and the
            operations op1, op2 ... are chained
            to the right of this expression object:
          
a op1 b
yields to the pseudo-code
expression1 = create-expression(a) expression2 = create-expression(expression1, op1, b)
            expression1 and expression2 keep track of their left
            and right operands, and the operation on those operands. The expressions
            keep also track of the result type of the associated sub-expression.
            In the above example, expression1
            and expression2 have
            result type decltype(a)
            and decltype(a op1
            b)
            respectively. The result type allows for chaining sub-expressions.
          
            The C++ operators precedence rules apply in any case. What is seen by
            the expression is what is reachable with left-to-right composition. Any
            other operation that happens before it reaches the expression's right
            operand is not parsed as a sub-expression and is seen as a single operand:
            the right operand is not developed further by the framework. Let's suppose
            op2 below has higher
            precedence than op1,
            then
          
a op1 b op2 c
is equivalent to:
create-expression(create-expression(a), op1, (b op2 c))
            In the above statement, the final expression can only see the result
            of (b
            op2 c) to its right, for which no further detail
            can be provided in the logs. This is also the case for right-to-left
            associative operators, such as !,
            ~, -
            (unary negation) etc.
          
| ![[Caution]](../../../../../../doc/src/images/caution.png) | Caution | 
|---|---|
| 
              Since the  | 
Once the full expression chain is built, it is evaluated as a chain of sub-expressions from left-to-right, exactly as the composition rule above. The evaluated elements are the ones of the expression itself. The expression
a op1 b
yields to the following evaluation chain:
expression2.result = expression1.result op1 b expression1.result = a
The final expression of the statement is cast to a boolean, which is in turn evaluated by the Unit Test Framework.
The example below illustrates the construction of the left-to-right chained expression.
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_macro2 #include <boost/test/included/unit_test.hpp> BOOST_AUTO_TEST_CASE( test_op_precedence ) { int a = 13, b = 2, c = 12; // left term of == is expanded in the logs BOOST_TEST(a % b == c); // right term of == is not expanded in the logs BOOST_TEST(a == c % b); } BOOST_AUTO_TEST_CASE( test_op_right_associative ) { int a = 1; BOOST_TEST(a); BOOST_TEST(!a); BOOST_TEST(--a); } | 
| Output | 
|---|
| > ./boost_test_macro2 --log_level=all Running 2 test cases... test.cpp(16): error: in "test_op_precedence": check a % b == c has failed [13 % 2 != 12] test.cpp(18): error: in "test_op_precedence": check a == c % b has failed [13 != 0] test.cpp(25): error: in "test_op_right_associative": check !a has failed test.cpp(26): error: in "test_op_right_associative": check --a has failed [(bool)0 is false] *** 4 failures are detected in the test module "boost_test_macro2" |