• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
2 / Copyright (c) 2015 Boost.Test contributors
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 /]
7
8[section:collections Collections comparison]
9
10Instead of comparing a single value against another, there is often a need for comparing /collections/ of values.
11A collection and indirectly the values it contains may be considered in several ways:
12
13* collection as a /sequence of values/: this is the case for instance when `N` values are stored in a
14  container. Containers in this case are used for storing several values, and iterating over the containers yields
15  sequences that can be compared *element-wise*. The iteration should be in an order that is /a priori/ known
16  [footnote this might not be the case
17  for e.g. `std::unordered_map`, for which the buckets might be filled differently depending on the insertion order.],
18  for being able to compare the sequences. The values in the collection are independent each other, and subsets can be compared as well.
19* collection as an /ensemble/: this is the case where the elements of the collection define an /entity/,
20  and no element can be dissociated from the others.
21  An example would be a collection of letters for a specific word in the natural language; in this settings
22  any of the character in the word/collection depends /semantically/ on the other and it is not possible to take
23  a subset of it without breaking the meaning of the word. Another example would be a vector of size `N` representing a
24  point in a `N` dimensional space, compared to another point with the relation "`<`": the comparison is application
25  specific and a possible comparison would be the lexicographical ordering
26  [footnote in this case `v_a < v_b` means that the point `v_a` is inside the rectangle (origin, `v_b`)].
27
28The following observations can be done:
29
30* the methods employed for comparing collections should be chosen adequately with the meaning of the collection,
31* comparing sequences *element-wise* often involves writing loops in the test body, and if a dedicated tool is already in place
32  the test body would gain in clarity and expressiveness (including the report in case of failure),
33* some comparison methods such as the lexicographical one, have good general behavior (e.g. total ordering,
34  defined for collections of different size), but are sometimes inappropriate.
35
36__BOOST_TEST__ provides specific tools for comparing collections:
37
38* using the /native/ [footnote either defined by the container or by the user] operator of the container of the collection,
39  which is mentioned as the [link ref_boost_test_coll_default_comp /default behavior/].
40* using [link boost_test_coll_perelement element-wise] comparison for which extended failure diagnostic is provided,
41* and using [link boost_test_coll_default_lex lexicographical] comparison for which extended failure diagnostic is provided,
42
43More details about the concept of /collection/ in the __UTF__ is given [link what_is_a_collection /here/].
44
45[#ref_boost_test_coll_default_comp][h3 Default comparison]
46The default comparison dispatches to the existing overloaded comparison operator. The __UTF__ distinguishes two use cases
47
48# none of the comparison operand is a C-Array, in which case we use the [link ref_boost_test_coll_default_comp_container container default behavior]
49# one of the comparison operand is a C-array, in which case we [link ref_boost_test_coll_c_arrays mimic `std::vector`] behavior
50
51[#ref_boost_test_coll_default_comp_container][h4 Container default behavior]
52Given two containers `c_a` and `c_b` that are not C-arrays,
53
54``
55BOOST_TEST(c_a op c_b)
56``
57
58is equivalent, in terms of test success, to
59
60``
61auto result = c_a op c_b;
62BOOST_TEST(result);
63``
64
65In the example below, `operator==` is not defined for `std::vector` of different types, and the program would fail to
66compile if the corresponding lines were uncommented (`std::vector` uses lexicographical comparison by default).
67
68[note In the case of default comparison, there is no additional diagnostic provided by the __UTF__. See the section
69[link ref_boost_test_coll_special_macro `BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE`] below.]
70
71[bt_example boost_test_container_default..BOOST_TEST containers comparison default..run-fail]
72
73[#ref_boost_test_coll_c_arrays][h4 C-arrays default behavior]
74As soon as one of the operands is a C-array, there is no /default behavior/ the __UTF__ can dispatch to.
75This is why in that case, the comparison mimics the `std::vector` behavior.
76
77[bt_example boost_test_macro_container_c_array..BOOST_TEST C-arrays..run-fail]
78
79[#boost_test_coll_perelement][h3 Element-wise comparison]
80By specifying the manipulator [classref boost::test_tools::per_element], the comparison of the elements of the containers
81are performed /element-wise/, in the order given by the forward iterators of the containers. This is a comparison on
82the /sequences/ of elements generated by the containers, for which the __UTF__ provides advanced diagnostic.
83
84In 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.
85Those sequences correspond to the content of the respective containers, in the order given by their iterator. Let
86`op` be one of the [link boost_test_statement_overloads binary comparison operators].
87
88``
89BOOST_TEST(c_a op c_b, boost::test_tools::per_element() );
90``
91
92is equivalent to
93
94``
95if(c_a.size() == c_b.size())
96{
97  for(int i=0; i < c_a.size(); i++)
98  {
99    __BOOST_TEST_CONTEXT__("index " << i)
100    {
101      BOOST_TEST(a_i op b_i);
102    }
103  }
104}
105else
106{
107  BOOST_TEST(c_a.size() == c_b.size());
108}
109``
110
111[warning this is fundamentally different from using the containers' default comparison operators (default behavior).]
112[warning this is not an order relationship on containers. As a side effect, it is possible to have
113 ``BOOST_TEST(c_a == c_b)`` and ``BOOST_TEST(c_a != c_b)`` failing at the same time]
114
115Sequences are compared using the specified operator `op`, evaluated on the left and right elements of the respective sequences.
116The order of the compared elements is given by the iterators of the respective containers [footnote the containers should yield the same
117sequences for a fixed set of elements they contain].
118In case of failure, the indices of the elements failing `op` are returned.
119
120[bt_example boost_test_sequence_per_element..BOOST_TEST sequence comparison..run-fail]
121
122[h4 Requirements]
123For the sequences to be comparable element-wise, the following conditions should be met:
124
125* the containers should meet the [link what_is_a_collection sequence] definition,
126* the containers should yield the same number of elements,
127* `op` should be one of the comparison operator `==`, `!=`, `<`, `<=`, `>`, `>=`
128* the `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
129  of the respective collections.
130
131[caution the resulting type of "`c_a == c_b`" is an [classref boost::test_tools::assertion_result assertion_result]: it is not
132 possible to compose more that one comparison on the `BOOST_TEST` statement:
133
134 ``
135   BOOST_TEST(c_a == c_b == 42, boost::test_tools::per_element() ); // does not compile
136 ``]
137
138[#boost_test_coll_default_lex][h3 Lexicographic comparison]
139By specifying the manipulator [classref boost::test_tools::lexicographic], the containers are compared using the /lexicographical/
140order and for which the __UTF__ provides additional diagnostic in case of failure.
141
142``
143BOOST_TEST(c_a op c_b, boost::test_tools::lexicographic() );
144``
145
146The comparison is performed in the order given by forward iterators of the containers.
147
148[tip lexicographic comparison yields a total order on the containers: the statements `c_a < c_b` and
149 `c_b <= c_a` are mutually exclusive.]
150
151[note The equality `==` and inequality `!=` are not available for this type of comparison.]
152
153[bt_example boost_test_container_lex..BOOST_TEST container comparison using lexicographical order..run-fail]
154
155
156[#ref_boost_test_coll_special_macro][h3 Extended diagnostic by default for specific containers]
157
158As seen above,
159
160* for testing equality, the `==` relation is either explicit (using `boost::test_tools::per_element()`) or
161  implicit when the container overloads/implements this type of comparison,
162* for testing inequality, lexicographical comparison for `<` (and derived operations) is either explicit
163  (using `boost::test_tools::lexicographic()`) or implicit when
164  the container overloads/implements uses this type of comparison.
165
166When the default is to using the container implementation, it is not possible to benefit from an extended failure diagnostic.
167The __UTF__ provides a mechanism for performing the same comparisons through the __UTF__ instead of the container operator,
168through the macro `BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE` that might be used as follow:
169
170[bt_example boost_test_container_lex_default..Default `std::vector<int>` to lexicographic with extended diagnostic..run-fail]
171
172[h4 Requirements]
173
174* the containers should meet the [link what_is_a_collection sequence] definition,
175* the containers should be of the exact same type
176* `op` should be one of the comparison operator `==`, `!=`, `<`, `<=`, `>`, `>=`
177
178[note Note that the operation `!=` is in this case not an element-wise comparison, ]
179
180
181[#what_is_a_collection][h3 What is a sequence?]
182A /sequence/ is given by the iteration over a /forward iterable/ container. A forward iterable container is:
183
184* either a C-array,
185* or a `class`/`struct` that implements the member functions `begin` and `end`.
186
187For collection comparisons, both sequences are also required to be different than `string` sequences. In that case, the sequences are
188dispatched to string [link boost_test.testing_tools.extended_comparison.strings comparison instead].
189
190[warning `string` (or `wstring`) meets the sequence concept by definition, but their handling with __BOOST_TEST__ is done differently.
191 See [link boost_test.testing_tools.extended_comparison.strings Strings and C-strings comparison] for more details.]
192
193[tip If the behavior of __BOOST_TEST__ is not the one you expect, you can always use raw comparison. See [link boost_test_statement_limitations this section]
194 for details.]
195
196[note Since [link ref_CHANGE_LOG_3_6 Boost.Test 3.6] (Boost 1.65) the requirements for the collection concepts have been relaxed to
197 include C-arrays as well]
198[note Since [link ref_CHANGE_LOG_3_7 Boost.Test 3.7] (Boost 1.67) the definition of `const_iterator` and `value_type` in the collection
199 type is not required anymore (for the compilers properly supporting `decltype`). ]
200
201The detection of the types that meet these requirements containers is delegated to the class [classref boost::unit_test::is_forward_iterable],
202which for C++11 detects the required member functions and fields. However for C++03, the types providing the sequences should be explicitly
203indicated to the __UTF__ by a specialization of [classref boost::unit_test::is_forward_iterable]
204[footnote Standard containers of the `STL` are recognized as /forward iterable/ container.].
205
206[endsect] [/ sequences]
207