1 | // Copyright Neil Groves 2009. Use, modification and |
2 | // distribution is subject to the Boost Software License, Version |
3 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
4 | // http://www.boost.org/LICENSE_1_0.txt) |
5 | // |
6 | // |
7 | // For more information, see http://www.boost.org/libs/range/ |
8 | // |
9 | #ifndef BOOST_RANGE_TEST_TEST_DRIVER_RANGE_RETURN_TEST_DRIVER_HPP_INCLUDED |
10 | #define BOOST_RANGE_TEST_TEST_DRIVER_RANGE_RETURN_TEST_DRIVER_HPP_INCLUDED |
11 | |
12 | #include <boost/assert.hpp> |
13 | #include <boost/test/test_tools.hpp> |
14 | #include <boost/test/unit_test.hpp> |
15 | |
16 | namespace boost |
17 | { |
18 | namespace range_test |
19 | { |
20 | // check the results of an algorithm that returns |
21 | // a range_return. |
22 | // |
23 | // This version is the general version. It should never be called. |
24 | // All calls should invoke specialized implementations. |
25 | template< range_return_value return_type > |
26 | struct check_results |
27 | { |
28 | template< class Container, class Iterator > |
29 | static void test( |
30 | Container& test, |
31 | Container& reference, |
32 | Iterator test_it, |
33 | Iterator reference_it |
34 | ) |
35 | { |
36 | BOOST_ASSERT( false ); |
37 | } |
38 | }; |
39 | |
40 | // check the results of an algorithm that returns |
41 | // a 'found' iterator |
42 | template< > |
43 | struct check_results<return_found> |
44 | { |
45 | template< class Container, class Iterator > |
46 | static void test( |
47 | Container& test, |
48 | Container& reference, |
49 | Iterator test_it, |
50 | Iterator reference_it |
51 | ) |
52 | { |
53 | BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), |
54 | test.begin(), test.end() ); |
55 | |
56 | BOOST_CHECK_EQUAL( std::distance(test.begin(), test_it), |
57 | std::distance(reference.begin(), reference_it) ); |
58 | } |
59 | }; |
60 | |
61 | // check the results of an algorithm that returns |
62 | // a 'next(found)' iterator |
63 | template< > |
64 | struct check_results<return_next> |
65 | { |
66 | template< class Container, class Iterator > |
67 | static void test( |
68 | Container& test, |
69 | Container& reference, |
70 | Iterator test_it, |
71 | Iterator reference_it |
72 | ) |
73 | { |
74 | BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), |
75 | test.begin(), test.end() ); |
76 | |
77 | if (reference_it == reference.end()) |
78 | { |
79 | BOOST_CHECK( test_it == test.end() ); |
80 | } |
81 | else |
82 | { |
83 | BOOST_CHECK_EQUAL( |
84 | std::distance(test.begin(), test_it), |
85 | std::distance(reference.begin(), reference_it) + 1); |
86 | } |
87 | } |
88 | }; |
89 | |
90 | // check the results of an algorithm that returns |
91 | // a 'prior(found)' iterator |
92 | template< > |
93 | struct check_results<return_prior> |
94 | { |
95 | template< class Container, class Iterator > |
96 | static void test( |
97 | Container& test, |
98 | Container& reference, |
99 | Iterator test_it, |
100 | Iterator reference_it |
101 | ) |
102 | { |
103 | BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), |
104 | test.begin(), test.end() ); |
105 | |
106 | if (reference_it == reference.begin()) |
107 | { |
108 | BOOST_CHECK( test_it == test.begin() ); |
109 | } |
110 | else |
111 | { |
112 | BOOST_CHECK_EQUAL( |
113 | std::distance(test.begin(), test_it) + 1, |
114 | std::distance(reference.begin(), reference_it)); |
115 | } |
116 | } |
117 | }; |
118 | |
119 | // check the results of an algorithm that returns |
120 | // a '[begin, found)' range |
121 | template< > |
122 | struct check_results<return_begin_found> |
123 | { |
124 | template< class Container, class Iterator > |
125 | static void test( |
126 | Container& test, |
127 | Container& reference, |
128 | iterator_range<Iterator> test_rng, |
129 | Iterator reference_it |
130 | ) |
131 | { |
132 | BOOST_CHECK_EQUAL_COLLECTIONS( |
133 | reference.begin(), reference.end(), |
134 | test.begin(), test.end() |
135 | ); |
136 | |
137 | BOOST_CHECK( test_rng.begin() == test.begin() ); |
138 | |
139 | BOOST_CHECK_EQUAL_COLLECTIONS( |
140 | reference.begin(), reference_it, |
141 | boost::begin(test_rng), boost::end(test_rng) |
142 | ); |
143 | } |
144 | }; |
145 | |
146 | // check the results of an algorithm that returns |
147 | // a '[begin, next(found))' range |
148 | template< > |
149 | struct check_results<return_begin_next> |
150 | { |
151 | template< class Container, class Iterator > |
152 | static void test( |
153 | Container& test, |
154 | Container& reference, |
155 | iterator_range<Iterator> test_rng, |
156 | Iterator reference_it |
157 | ) |
158 | { |
159 | BOOST_CHECK_EQUAL_COLLECTIONS( |
160 | reference.begin(), reference.end(), |
161 | test.begin(), test.end() |
162 | ); |
163 | |
164 | BOOST_CHECK( test_rng.begin() == test.begin() ); |
165 | |
166 | if (reference_it == reference.end()) |
167 | { |
168 | BOOST_CHECK( test_rng.end() == test.end() ); |
169 | } |
170 | else |
171 | { |
172 | BOOST_CHECK_EQUAL_COLLECTIONS( |
173 | reference.begin(), boost::next(reference_it), |
174 | test_rng.begin(), test_rng.end()); |
175 | } |
176 | } |
177 | }; |
178 | |
179 | // check the results of an algorithm that returns |
180 | // a '[begin, prior(found))' range |
181 | template< > |
182 | struct check_results<return_begin_prior> |
183 | { |
184 | template< class Container, class Iterator > |
185 | static void test( |
186 | Container& test, |
187 | Container& reference, |
188 | iterator_range<Iterator> test_rng, |
189 | Iterator reference_it |
190 | ) |
191 | { |
192 | BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), |
193 | test.begin(), test.end() ); |
194 | |
195 | BOOST_CHECK( test_rng.begin() == test.begin() ); |
196 | |
197 | if (reference_it == reference.begin()) |
198 | { |
199 | BOOST_CHECK( boost::end(test_rng) == test.begin() ); |
200 | } |
201 | else |
202 | { |
203 | BOOST_CHECK_EQUAL( std::distance(boost::begin(test_rng), boost::end(test_rng)) + 1, |
204 | std::distance(reference.begin(), reference_it) ); |
205 | } |
206 | } |
207 | }; |
208 | |
209 | // check the results of an algorithm that returns |
210 | // a '[found, end)' range |
211 | template< > |
212 | struct check_results<return_found_end> |
213 | { |
214 | template< class Container, class Iterator > |
215 | static void test( |
216 | Container& test, |
217 | Container& reference, |
218 | iterator_range<Iterator> test_rng, |
219 | Iterator reference_it |
220 | ) |
221 | { |
222 | BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), |
223 | test.begin(), test.end() ); |
224 | |
225 | BOOST_CHECK_EQUAL( |
226 | std::distance(test.begin(), boost::begin(test_rng)), |
227 | std::distance(reference.begin(), reference_it)); |
228 | |
229 | BOOST_CHECK( boost::end(test_rng) == test.end() ); |
230 | } |
231 | }; |
232 | |
233 | // check the results of an algorithm that returns |
234 | // a '[next(found), end)' range |
235 | template< > |
236 | struct check_results<return_next_end> |
237 | { |
238 | template< class Container, class Iterator > |
239 | static void test( |
240 | Container& test, |
241 | Container& reference, |
242 | iterator_range<Iterator> test_rng, |
243 | Iterator reference_it |
244 | ) |
245 | { |
246 | BOOST_CHECK_EQUAL_COLLECTIONS( |
247 | reference.begin(), reference.end(), |
248 | test.begin(), test.end() |
249 | ); |
250 | |
251 | BOOST_CHECK( test_rng.end() == test.end() ); |
252 | |
253 | if (reference_it == reference.end()) |
254 | { |
255 | BOOST_CHECK( test_rng.begin() == test.end() ); |
256 | } |
257 | else |
258 | { |
259 | BOOST_CHECK_EQUAL_COLLECTIONS( |
260 | boost::next(reference_it), reference.end(), |
261 | test_rng.begin(), test_rng.end() |
262 | ); |
263 | } |
264 | } |
265 | }; |
266 | |
267 | // check the results of an algorithm that returns |
268 | // a 'prior(found), end)' range |
269 | template< > |
270 | struct check_results<return_prior_end> |
271 | { |
272 | template< class Container, class Iterator > |
273 | static void test( |
274 | Container& test, |
275 | Container& reference, |
276 | iterator_range<Iterator> test_rng, |
277 | Iterator reference_it |
278 | ) |
279 | { |
280 | BOOST_CHECK_EQUAL_COLLECTIONS( |
281 | reference.begin(), reference.end(), |
282 | test.begin(), test.end() |
283 | ); |
284 | |
285 | BOOST_CHECK( test_rng.end() == test.end() ); |
286 | |
287 | if (reference_it == reference.begin()) |
288 | { |
289 | BOOST_CHECK( test_rng.begin() == test.begin() ); |
290 | } |
291 | else |
292 | { |
293 | BOOST_CHECK_EQUAL_COLLECTIONS( |
294 | boost::prior(reference_it), reference.end(), |
295 | test_rng.begin(), test_rng.end() |
296 | ); |
297 | } |
298 | } |
299 | }; |
300 | |
301 | // check the results of an algorithm that returns |
302 | // a '[begin, end)' range |
303 | template< > |
304 | struct check_results<return_begin_end> |
305 | { |
306 | template< class Container, class Iterator > |
307 | static void test( |
308 | Container& test, |
309 | Container& reference, |
310 | iterator_range<Iterator> test_rng, |
311 | Iterator reference_it |
312 | ) |
313 | { |
314 | BOOST_CHECK_EQUAL_COLLECTIONS( |
315 | reference.begin(), reference.end(), |
316 | test.begin(), test.end() |
317 | ); |
318 | |
319 | BOOST_CHECK( test_rng.begin() == test.begin() ); |
320 | BOOST_CHECK( test_rng.end() == test.end() ); |
321 | } |
322 | }; |
323 | |
324 | // A test driver to exercise a test through all of the range_return |
325 | // combinations. |
326 | // |
327 | // The test driver also contains the code required to check the |
328 | // return value correctness. |
329 | // |
330 | // The TestPolicy needs to implement two functions: |
331 | // |
332 | // - perform the boost range version of the algorithm that returns |
333 | // a range_return<Container,return_type>::type |
334 | // template<range_return_value return_type, class Container> |
335 | // BOOST_DEDUCED_TYPENAME range_return<Container,return_type>::type |
336 | // test(Container& cont); |
337 | // |
338 | // - perform the reference std version of the algorithm that |
339 | // returns the standard iterator result |
340 | // template<class Container> |
341 | // BOOST_DEDUCED_TYPENAME range_iterator<Container>::type |
342 | // reference(Container& cont); |
343 | class range_return_test_driver |
344 | { |
345 | public: |
346 | template< class Container, |
347 | class TestPolicy > |
348 | void operator()(Container& cont, TestPolicy policy) |
349 | { |
350 | test_range_iter (cont, policy); |
351 | test_range<return_found,Container,TestPolicy> ()(cont, policy); |
352 | test_range<return_next,Container,TestPolicy> ()(cont, policy); |
353 | test_range<return_prior,Container,TestPolicy> ()(cont, policy); |
354 | test_range<return_begin_found,Container,TestPolicy>()(cont, policy); |
355 | test_range<return_begin_next,Container,TestPolicy> ()(cont, policy); |
356 | test_range<return_begin_prior,Container,TestPolicy>()(cont, policy); |
357 | test_range<return_found_end,Container,TestPolicy> ()(cont, policy); |
358 | test_range<return_next_end,Container,TestPolicy> ()(cont, policy); |
359 | test_range<return_prior_end,Container,TestPolicy> ()(cont, policy); |
360 | test_range<return_begin_end,Container,TestPolicy> ()(cont, policy); |
361 | } |
362 | |
363 | private: |
364 | template< class Container, class TestPolicy > |
365 | void test_range_iter( |
366 | Container& cont, |
367 | TestPolicy policy |
368 | ) |
369 | { |
370 | typedef BOOST_DEDUCED_TYPENAME range_iterator<Container>::type iterator_t; |
371 | |
372 | Container reference(cont); |
373 | Container test(cont); |
374 | |
375 | iterator_t range_result = policy.test_iter(test); |
376 | iterator_t reference_it = policy.reference(reference); |
377 | |
378 | check_results<return_found>::test(test, reference, |
379 | range_result, reference_it); |
380 | } |
381 | |
382 | template< range_return_value result_type, class Container, class TestPolicy > |
383 | struct test_range |
384 | { |
385 | void operator()(Container& cont, TestPolicy policy) |
386 | { |
387 | typedef BOOST_DEDUCED_TYPENAME range_iterator<Container>::type iterator_t; |
388 | typedef BOOST_DEDUCED_TYPENAME range_return<Container, result_type>::type range_return_t; |
389 | typedef BOOST_DEDUCED_TYPENAME TestPolicy::template test_range<result_type> test_range_t; |
390 | |
391 | Container reference(cont); |
392 | Container test_cont(cont); |
393 | |
394 | test_range_t test_range_fn; |
395 | range_return_t range_result = test_range_fn(policy, test_cont); |
396 | iterator_t reference_it = policy.reference(reference); |
397 | |
398 | check_results<result_type>::test(test_cont, reference, |
399 | range_result, reference_it); |
400 | } |
401 | }; |
402 | }; |
403 | } |
404 | } |
405 | |
406 | #endif // include guard |
407 | |