|  | Home | Libraries | People | FAQ | More | 
Instead of comparing a single value against another, there is often a need for comparing collections of values. A collection and indirectly the values it contains may be considered in several ways:
N
              values are stored in a container. Containers in this case are used
              for storing several values, and iterating over the containers yields
              sequences that can be compared element-wise.
              The iteration should be in an order that is a priori
              known [10], for being able to compare the sequences. The values in
              the collection are independent each other, and subsets can be compared
              as well.
            N
              representing a point in a N
              dimensional space, compared to another point with the relation "<": the comparison is application
              specific and a possible comparison would be the lexicographical ordering
              [11].
            The following observations can be done:
          BOOST_TEST provides specific tools
          for comparing collections:
        
More details about the concept of collection in the Unit Test Framework is given here.
          The default comparison dispatches to the existing overloaded operator.
          Given two containers c_a
          and c_b,
        
BOOST_TEST(c_a op c_b)
is equivalent, in terms of test success, to
auto result = c_a op c_b; BOOST_TEST(result);
          In the example below, operator== is not defined for std::vector
          of different types, and the program would fail to compile if the corresponding
          lines were uncommented (std::vector
          uses lexicographical comparison by default).
        
| ![[Note]](../../../../../../../doc/src/images/note.png) | Note | 
|---|---|
| 
            In this case, there is no additional diagnostic provided by the Unit
            Test Framework. See the section  | 
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_sequence #include <boost/test/included/unit_test.hpp> #include <vector> BOOST_AUTO_TEST_CASE( test_collections_vectors ) { std::vector<int> a{1,2,3}, c{1,5,3,4}; std::vector<long> b{1,5,3}; // the following does not compile //BOOST_TEST(a == b); //BOOST_TEST(a <= b); // stl defaults to lexicographical comparison BOOST_TEST(a < c); BOOST_TEST(a >= c); BOOST_TEST(a != c); } | 
| Output | 
|---|
| > ./boost_test_container_default --log_level=all Running 1 test case... Entering test module "boost_test_sequence" test.cpp(13): Entering test case "test_collections_vectors" test.cpp(23): info: check a < c has passed test.cpp(24): error: in "test_collections_vectors": check a >= c has failed test.cpp(25): info: check a != c has passed test.cpp(13): Leaving test case "test_collections_vectors"; testing time: 208us Leaving test module "boost_test_sequence"; testing time: 286us *** 1 failure is detected in the test module "boost_test_container_default" | 
          By specifying the manipulator boost::test_tools::per_element,
          the comparison of the elements of the containers are performed element-wise,
          in the order given by the forward iterators of the containers. This is
          a comparison on the sequences of elements generated
          by the containers, for which the Unit Test Framework
          provides advanced diagnostic.
        
          In more details, let c_a = (a_1,... a_n) and c_b
          = (b_1,... b_n)
          be two sequences of same length, but not necessarily of same type. Those
          sequences correspond to the content of the respective containers, in the
          order given by their iterator. Let op
          be one of the binary comparison
          operators.
        
BOOST_TEST(c_a op c_b, boost::test_tools::per_element() );
is equivalent to
if(c_a.size() == c_b.size())
{
  for(int i=0; i < c_a.size(); i++)
  {
    BOOST_TEST_CONTEXT("index " << i)
    {
      BOOST_TEST(a_i op b_i);
    }
  }
}
else
{
  BOOST_TEST(c_a.size() == c_b.size());
}
| ![[Warning]](../../../../../../../doc/src/images/warning.png) | Warning | 
|---|---|
| this is fundamentally different from using the containers' default comparison operators (default behavior). | 
| ![[Warning]](../../../../../../../doc/src/images/warning.png) | Warning | 
|---|---|
| this is not an order relationship on containers. As a side effect, it is possible to have BOOST_TEST(c_a == c_b) and BOOST_TEST(c_a != c_b) failing at the same time | 
          Sequences are compared using the specified operator op,
          evaluated on the left and right elements of the respective sequences. The
          order of the compared elements is given by the iterators of the respective
          containers [13]. In case of failure, the indices of the elements failing op are returned.
        
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_sequence_per_element #include <boost/test/included/unit_test.hpp> #include <vector> #include <list> namespace tt = boost::test_tools; BOOST_AUTO_TEST_CASE( test_sequence_per_element ) { std::vector<int> a{1,2,3}; std::vector<long> b{1,5,3}; std::list<short> c{1,5,3,4}; BOOST_TEST(a == b, tt::per_element()); // nok: a[1] != b[1] BOOST_TEST(a != b, tt::per_element()); // nok: a[0] == b[0] ... BOOST_TEST(a <= b, tt::per_element()); // ok BOOST_TEST(b < c, tt::per_element()); // nok: size mismatch BOOST_TEST(b >= c, tt::per_element()); // nok: size mismatch BOOST_TEST(b != c, tt::per_element()); // nok: size mismatch } | 
| Output | 
|---|
| > ./boost_test_sequence_per_element Running 1 test case... test.cpp(21): error: in "test_sequence_per_element": check a == b has failed Mismatch at position 1: 2 != 5. test.cpp(23): error: in "test_sequence_per_element": check a != b has failed Mismatch at position 0: 1 == 1. Mismatch at position 2: 3 == 3. test.cpp(25): error: in "test_sequence_per_element": check b < c has failed Collections size mismatch: 3 != 4 test.cpp(26): error: in "test_sequence_per_element": check b >= c has failed Collections size mismatch: 3 != 4 test.cpp(27): error: in "test_sequence_per_element": check b != c has failed Collections size mismatch: 3 != 4 *** 5 failures are detected in the test module "boost_test_sequence_per_element" | 
For the sequences to be comparable element-wise, the following conditions should be met:
op should be one of
              the comparison operator ==,
              !=, <,
              <=, >,
              >=
            a_i op
              b_i should be defined, where
              the type of a_i and
              b_i are the type returned
              by the dereference operator of the respective collections.
            | ![[Caution]](../../../../../../../doc/src/images/caution.png) | Caution | 
|---|---|
| 
            the resulting type of " BOOST_TEST(c_a == c_b == 42, boost::test_tools::per_element() ); // does not compile | 
          By specifying the manipulator boost::test_tools::lexicographic,
          the containers are compared using the lexicographical
          order and for which the Unit Test Framework provides
          additional diagnostic in case of failure.
        
BOOST_TEST(c_a op c_b, boost::test_tools::lexicographic() );
The comparison is performed in the order given by forward iterators of the containers.
| ![[Tip]](../../../../../../../doc/src/images/tip.png) | Tip | 
|---|---|
| 
            lexicographic comparison yields a total order on the containers: the
            statements  | 
| ![[Note]](../../../../../../../doc/src/images/note.png) | Note | 
|---|---|
| 
            The equality  | 
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_container_lex #include <boost/test/included/unit_test.hpp> #include <vector> namespace tt = boost::test_tools; BOOST_AUTO_TEST_CASE( test_collections_vectors_lex ) { std::vector<int> a{1,2,3}, b{1,2,2}, c{1,2,3,4}; BOOST_TEST(a < a, tt::lexicographic()); BOOST_TEST(a < b, tt::lexicographic()); BOOST_TEST(a < c, tt::lexicographic()); BOOST_TEST(a >= c, tt::lexicographic()); // does not compile //BOOST_TEST(a == c, tt::lexicographic()); //BOOST_TEST(a != c, tt::lexicographic()); } | 
| Output | 
|---|
| > ./boost_test_container_lex --log_level=all Running 1 test case... Entering test module "boost_test_container_lex" test.cpp(15): Entering test case "test_collections_vectors_lex" test.cpp(19): error: in "test_collections_vectors_lex": check a < a has failed Collections appear to be equal. test.cpp(20): error: in "test_collections_vectors_lex": check a < b has failed Failure at position 2: 3 >= 2. test.cpp(21): info: check a < c has passed test.cpp(22): error: in "test_collections_vectors_lex": check a >= c has failed Second collection has extra trailing elements. test.cpp(15): Leaving test case "test_collections_vectors_lex"; testing time: 267us Leaving test module "boost_test_container_lex"; testing time: 341us *** 3 failures are detected in the test module "boost_test_container_lex" | 
          As seen above, the lexicographical comparison is either explicit (boost::test_tools::lexicographic())
          or implicit when the container operations uses this type of comparison.
          In the second case, it is however not possible to benefit from an extended
          diagnostic in case of failure.
        
          If the lexicographical comparison is the default for a specific container,
          it is possible to dispatch the comparison operations to the Unit
          Test Framework instead of the container operator. In order to
          default to the Unit Test Framework lexicographical
          comparison, the macro BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE
          might be used as follow:
        
std::vector<int>
          to lexicographic with extended diagnostic
        | Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_container_lex_default #include <boost/test/included/unit_test.hpp> #include <vector> namespace tt = boost::test_tools; BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(std::vector<int>) BOOST_AUTO_TEST_CASE( test_collections_vectors_lex ) { std::vector<int> a{1,2,3}, b{1,2,2}; std::vector<long int> c{1,2,3,5}, d{1,2,3,4}; BOOST_TEST(a < a); // extended diagnostic BOOST_TEST(a < b); // extended diagnostic BOOST_TEST(c < d); // no extended diagnostic } | 
| Output | 
|---|
| > ./boost_test_container_lex_default Running 1 test case... test.cpp:22: error: in "test_collections_vectors_lex": check a < a has failed. Collections appear to be equal. test.cpp:23: error: in "test_collections_vectors_lex": check a < b has failed. Failure at position 2: 3 >= 2. test.run-fail.cpp:24: error: in "test_collections_vectors_lex": check c < d has failed *** 3 failures are detected in the test module "boost_test_container_lex_default" | 
op should be one of
              the ordered comparison operator <,
              <=, >,
              >=
            A sequence is given by the iteration over a forward iterable container. A forward iterable container is a container (C++11):
size
              and begin, as well
              as the fields const_iterator
              and value_type
            value_type
              is not of type char or
              wchar_t
            To that respect, C-arrays are not forward iterable containers:
| Code | 
|---|
| #define BOOST_TEST_MODULE boost_test_container_c #include <boost/test/included/unit_test.hpp> #include <sstream> #include <map> #include <vector> BOOST_AUTO_TEST_CASE( test_collections_not_on_c_arrays ) { int a[] = {1, 2, 3}; int b[] = {1, 5, 3, 4}; BOOST_TEST(a == b); } | 
| Output | 
|---|
| > ./boost_test_macro_container_c_array --log_level=all Running 1 test case... Entering test module "boost_test_container_c" test.cpp(15): Entering test case "test_collections_not_on_c_arrays" test.cpp(19): error: in "test_collections_not_on_c_arrays": check a == b has failed [0x7fff526e5bc4 != 0x7fff526e5bb0] test.cpp(15): Leaving test case "test_collections_not_on_c_arrays"; testing time: 323us Leaving test module "boost_test_container_c"; testing time: 526us *** 1 failure is detected in the test module "boost_test_container_c" | 
          The detection of the containers is delegated to the class boost::unit_test::is_forward_iterable,
          which for C++11 detects the required member functions and fields. However
          for C++03, the types providing the sequences should be explicitly indicated
          to the Unit Test Framework by a specialization of
          boost::unit_test::is_forward_iterable
          [14].
        
[10] 
                this might not be the case for e.g. std::unordered_map,
                for which the buckets might be filled differently depending on the
                insertion order.
              
[11] 
                in this case v_a < v_b
                means that the point v_a
                is inside the rectangle (origin, v_b)
              
[12] either defined by the container or by the user
[13] the containers should yield the same sequences for a fixed set of elements they contain
[14] 
            Standard containers of the STL
            are recognized as collections.