]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 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 | [#boost_test_coll_default_comp][h3 Default comparison] | |
46 | The default comparison dispatches to the existing overloaded operator. Given two containers `c_a` and `c_b`, | |
47 | ||
48 | `` | |
49 | BOOST_TEST(c_a op c_b) | |
50 | `` | |
51 | ||
52 | is equivalent, in terms of test success, to | |
53 | ||
54 | `` | |
55 | auto result = c_a op c_b; | |
56 | BOOST_TEST(result); | |
57 | `` | |
58 | ||
59 | In the example below, `operator==` is not defined for `std::vector` of different types, and the program would fail to | |
60 | compile if the corresponding lines were uncommented (`std::vector` uses lexicographical comparison by default). | |
61 | ||
62 | [note In this case, there is no additional diagnostic provided by the __UTF__. See the section | |
63 | [link ref_boost_test_coll_special_macro `BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE`] below.] | |
64 | ||
65 | [bt_example boost_test_container_default..BOOST_TEST containers comparison default..run-fail] | |
66 | ||
67 | [#boost_test_coll_perelement][h3 Element-wise comparison] | |
68 | By specifying the manipulator [classref boost::test_tools::per_element], the comparison of the elements of the containers | |
69 | are performed /element-wise/, in the order given by the forward iterators of the containers. This is a comparison on | |
70 | the /sequences/ of elements generated by the containers, for which the __UTF__ provides advanced diagnostic. | |
71 | ||
72 | 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. | |
73 | Those sequences correspond to the content of the respective containers, in the order given by their iterator. Let | |
74 | `op` be one of the [link boost_test_statement_overloads binary comparison operators]. | |
75 | ||
76 | `` | |
77 | BOOST_TEST(c_a op c_b, boost::test_tools::per_element() ); | |
78 | `` | |
79 | ||
80 | is equivalent to | |
81 | ||
82 | `` | |
83 | if(c_a.size() == c_b.size()) | |
84 | { | |
85 | for(int i=0; i < c_a.size(); i++) | |
86 | { | |
87 | __BOOST_TEST_CONTEXT__("index " << i) | |
88 | { | |
89 | BOOST_TEST(a_i op b_i); | |
90 | } | |
91 | } | |
92 | } | |
93 | else | |
94 | { | |
95 | BOOST_TEST(c_a.size() == c_b.size()); | |
96 | } | |
97 | `` | |
98 | ||
99 | [warning this is fundamentally different from using the containers' default comparison operators (default behavior).] | |
100 | [warning this is not an order relationship on containers. As a side effect, it is possible to have | |
101 | ``BOOST_TEST(c_a == c_b)`` and ``BOOST_TEST(c_a != c_b)`` failing at the same time] | |
102 | ||
103 | Sequences are compared using the specified operator `op`, evaluated on the left and right elements of the respective sequences. | |
104 | The order of the compared elements is given by the iterators of the respective containers [footnote the containers should yield the same | |
105 | sequences for a fixed set of elements they contain]. | |
106 | In case of failure, the indices of the elements failing `op` are returned. | |
107 | ||
108 | [bt_example boost_test_sequence_per_element..BOOST_TEST sequence comparison..run-fail] | |
109 | ||
110 | [h4 Requirements] | |
111 | For the sequences to be comparable element-wise, the following conditions should be met: | |
112 | ||
113 | * the containers should meet the [link what_is_a_collection sequence] definition, | |
114 | * the containers should yield the same number of elements, | |
115 | * `op` should be one of the comparison operator `==`, `!=`, `<`, `<=`, `>`, `>=` | |
116 | * 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 | |
117 | of the respective collections. | |
118 | ||
119 | [caution the resulting type of "`c_a == c_b`" is an [classref boost::test_tools::assertion_result assertion_result]: it is not | |
120 | possible to compose more that one comparison on the `BOOST_TEST` statement: | |
121 | ||
122 | `` | |
123 | BOOST_TEST(c_a == c_b == 42, boost::test_tools::per_element() ); // does not compile | |
124 | ``] | |
125 | ||
126 | [#boost_test_coll_default_lex][h3 Lexicographic comparison] | |
127 | By specifying the manipulator [classref boost::test_tools::lexicographic], the containers are compared using the /lexicographical/ | |
128 | order and for which the __UTF__ provides additional diagnostic in case of failure. | |
129 | ||
130 | `` | |
131 | BOOST_TEST(c_a op c_b, boost::test_tools::lexicographic() ); | |
132 | `` | |
133 | ||
134 | The comparison is performed in the order given by forward iterators of the containers. | |
135 | ||
136 | [tip lexicographic comparison yields a total order on the containers: the statements `c_a < c_b` and | |
137 | `c_b <= c_a` are mutually exclusive.] | |
138 | ||
139 | [bt_example boost_test_container_lex..BOOST_TEST container comparison using lexicographical order..run-fail] | |
140 | ||
141 | ||
142 | [#ref_boost_test_coll_special_macro][h4 Extended diagnostic by default for specific containers] | |
143 | ||
144 | As seen above, the lexicographical comparison is either explicit (`boost::test_tools::lexicographic()`) or implicit when | |
145 | the container operations uses this type of comparison. In the second case, it is however not possible to benefit from an extended | |
146 | diagnostic in case of failure. | |
147 | ||
148 | If the lexicographical comparison is the default for a specific container, it is possible to dispatch the comparison | |
149 | operations to the __UTF__ instead of the container operator. In order to default to the __UTF__ lexicographical comparison, | |
150 | the macro `BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE` might be used as follow: | |
151 | ||
152 | [bt_example boost_test_container_lex_default..Default `std::vector<int>` to lexicographic with extended diagnostic..run-fail] | |
153 | ||
154 | [h4 Requirements] | |
155 | ||
156 | * the containers should meet the [link what_is_a_collection sequence] definition, | |
157 | * the containers should be of the exact same type | |
158 | * `op` should be one of the ordered comparison operator `<`, `<=`, `>`, `>=` | |
159 | ||
160 | ||
161 | [#what_is_a_collection][h3 What is a sequence?] | |
162 | A sequence is given by the iteration over a /forward iterable/ container. A forward iterable container is a container (C++11): | |
163 | ||
164 | * that implements the member functions `size` and `begin`, as well as the fields `const_iterator` and `value_type` | |
165 | * and for which `value_type` is not of type `char` or `wchar_t` | |
166 | ||
167 | To that respect, C-arrays are *not* forward iterable containers: | |
168 | [bt_example boost_test_macro_container_c_array..BOOST_TEST C-arrays..run-fail] | |
169 | ||
170 | The detection of the containers is delegated to the class [classref boost::unit_test::is_forward_iterable], which for C++11 | |
171 | detects the required member functions and fields. However for C++03, the types providing the sequences should be explicitly indicated | |
172 | to the __UTF__ by a specialization of [classref boost::unit_test::is_forward_iterable] | |
173 | [footnote Standard containers of the `STL` are recognized as collections.]. | |
174 | ||
175 | [endsect] [/ sequences] |