Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / test / doc / testing_tools / boost_test_collection_comparison.qbk
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
10 Instead of comparing a single value against another, there is often a need for comparing /collections/ of values.
11 A 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
28 The 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
43 More 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]
46 The 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]
52 Given two containers `c_a` and `c_b` that are not C-arrays,
53
54 ``
55 BOOST_TEST(c_a op c_b)
56 ``
57
58 is equivalent, in terms of test success, to
59
60 ``
61 auto result = c_a op c_b;
62 BOOST_TEST(result);
63 ``
64
65 In the example below, `operator==` is not defined for `std::vector` of different types, and the program would fail to
66 compile 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]
74 As soon as one of the operands is a C-array, there is no /default behavior/ the __UTF__ can dispatch to.
75 This 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]
80 By specifying the manipulator [classref boost::test_tools::per_element], the comparison of the elements of the containers
81 are performed /element-wise/, in the order given by the forward iterators of the containers. This is a comparison on
82 the /sequences/ of elements generated by the containers, for which the __UTF__ provides advanced diagnostic.
83
84 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.
85 Those 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 ``
89 BOOST_TEST(c_a op c_b, boost::test_tools::per_element() );
90 ``
91
92 is equivalent to
93
94 ``
95 if(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 }
105 else
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
115 Sequences are compared using the specified operator `op`, evaluated on the left and right elements of the respective sequences.
116 The order of the compared elements is given by the iterators of the respective containers [footnote the containers should yield the same
117 sequences for a fixed set of elements they contain].
118 In 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]
123 For 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]
139 By specifying the manipulator [classref boost::test_tools::lexicographic], the containers are compared using the /lexicographical/
140 order and for which the __UTF__ provides additional diagnostic in case of failure.
141
142 ``
143 BOOST_TEST(c_a op c_b, boost::test_tools::lexicographic() );
144 ``
145
146 The 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
158 As 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
166 When the default is to using the container implementation, it is not possible to benefit from an extended failure diagnostic.
167 The __UTF__ provides a mechanism for performing the same comparisons through the __UTF__ instead of the container operator,
168 through 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?]
182 A /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
187 For collection comparisons, both sequences are also required to be different than `string` sequences. In that case, the sequences are
188 dispatched 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
201 The detection of the types that meet these requirements containers is delegated to the class [classref boost::unit_test::is_forward_iterable],
202 which for C++11 detects the required member functions and fields. However for C++03, the types providing the sequences should be explicitly
203 indicated 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]