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
16namespace 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

source code of boost/libs/range/test/test_driver/range_return_test_driver.hpp