1 /*=============================================================================
2 Copyright (c) 2003 Giovanni Bajo
3 http://spirit.sourceforge.net/
4
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9
10 #include <boost/detail/lightweight_test.hpp>
11 #include <iostream>
12 #include <vector>
13 #include <string>
14 #include <list>
15 #include <algorithm>
16 #include <iterator>
17 #include <cstddef>
18 #include <boost/config.hpp>
19 #include <boost/concept_check.hpp>
20 #include <boost/mpl/if.hpp>
21 #include <boost/mpl/list.hpp>
22 #include <boost/mpl/for_each.hpp>
23
24 // Our baby
25 #include <boost/spirit/include/classic_position_iterator.hpp>
26
27 using namespace std;
28 using namespace BOOST_SPIRIT_CLASSIC_NS;
29 namespace mpl = boost::mpl;
30
31 ///////////////////////////////////////////////////////////////////////////////
32 namespace test_impl {
33
34 template <typename IterT>
InstanciateTestOne(void)35 void InstanciateTestOne(void)
36 {
37 IterT();
38
39 // Check that the iterator is a full non-mutable forward iterator
40 typedef boost::ForwardIteratorConcept<IterT> concept_t;
41 boost::function_requires<concept_t>();
42 }
43
44 struct InstanciateTest
45 {
46 template <typename BaseIterT>
operator ()test_impl::InstanciateTest47 void operator()(BaseIterT )
48 {
49 InstanciateTestOne<position_iterator<BaseIterT> >();
50 InstanciateTestOne<position_iterator2<BaseIterT> >();
51 InstanciateTestOne<position_iterator<BaseIterT, file_position_without_column> >();
52 InstanciateTestOne<position_iterator2<BaseIterT, file_position_without_column> >();
53 }
54 };
55
56 ///////////////////////////////////////////////////////////////////////////////
57 } /* namespace test_impl */
58
59 // These tests are defined after main() to be absolutely sure that the
60 // instantiation test will happen before any other (since it's mainly
61 // a compile-time test).
62 void CheckInstantiation(void);
63 void CheckConstructors(void);
64 void CheckBasicFunctionality(void);
65 void CheckColumnCounting(void);
66 void CheckLineExtraction(void);
67 void CheckDistance(void);
68 void CheckSingular();
69
CheckInstantiation(void)70 void CheckInstantiation(void)
71 {
72 typedef mpl::list
73 <
74 char*
75 ,const char*
76 ,string::iterator
77 ,string::const_iterator
78 > iter_list_t;
79
80 mpl::for_each<iter_list_t>(test_impl::InstanciateTest());
81 }
82
main(void)83 int main(void)
84 {
85 CheckInstantiation();
86 CheckConstructors();
87 CheckBasicFunctionality();
88 CheckColumnCounting();
89 CheckLineExtraction();
90 CheckDistance();
91 CheckSingular();
92
93 return boost::report_errors();
94 }
95
96 ///////////////////////////////////////////////////////////////////////////////
97 namespace test_impl {
98
99 template <typename IterT>
CheckIncrement(IterT iter)100 void CheckIncrement(IterT iter)
101 {
102 IterT end;
103
104 // Check also that copy construction and assignment do not
105 // interfere with increment
106 IterT iter2(iter);
107 IterT iter3 = iter;
108
109 BOOST_TEST(iter != end);
110 BOOST_TEST(iter2 != end);
111 BOOST_TEST(iter3 != end);
112 BOOST_TEST(*iter == '0');
113
114 ++iter;
115 ++iter2;
116 ++iter3;
117 BOOST_TEST(iter == iter2);
118 BOOST_TEST(iter == iter3);
119 BOOST_TEST(*iter == *iter2);
120 BOOST_TEST(*iter == *iter3);
121 BOOST_TEST(iter.get_position() == iter2.get_position());
122 BOOST_TEST(iter.get_position() == iter3.get_position());
123 BOOST_TEST(*iter == '1');
124
125 BOOST_TEST(*iter++ == '1');
126 BOOST_TEST(*iter2++ == '1');
127 BOOST_TEST(*iter3++ == '1');
128 BOOST_TEST(*iter == *iter2);
129 BOOST_TEST(*iter == *iter3);
130 BOOST_TEST(iter.get_position() == iter2.get_position());
131 BOOST_TEST(iter.get_position() == iter3.get_position());
132 BOOST_TEST(*iter == '2');
133
134 ++iter; ++iter; ++iter; ++iter; ++iter; ++iter; ++iter;
135 BOOST_TEST(*iter == '9');
136 ++iter;
137 BOOST_TEST(iter == end);
138
139 // Check that one after end is no more end
140 ++iter;
141 BOOST_TEST(iter != end);
142 }
143
144 template <typename IterT>
CheckLineCounting(IterT iter)145 void CheckLineCounting(IterT iter)
146 {
147 IterT end;
148
149 BOOST_TEST(*iter == '\n');
150 BOOST_TEST(iter.get_position().line == 1);
151 ++iter; // 0
152 BOOST_TEST(iter.get_position().line == 2);
153 ++iter; // 1
154 ++iter; // 2
155 ++iter; // 3
156 ++iter; // \r
157 BOOST_TEST(*iter == '\r');
158 BOOST_TEST(iter.get_position().line == 2);
159 ++iter; // \n
160 BOOST_TEST(*iter == '\n');
161 BOOST_TEST(iter.get_position().line == 2);
162 ++iter; // 4
163 BOOST_TEST(iter.get_position().line == 3);
164 ++iter; // 5
165 ++iter; // 6
166 ++iter; // 7
167 ++iter; // \n
168 BOOST_TEST(*iter == '\n');
169 BOOST_TEST(iter.get_position().line == 3);
170 ++iter; // 8
171 BOOST_TEST(iter.get_position().line == 4);
172 ++iter; // 9
173 ++iter; // \n
174 BOOST_TEST(iter.get_position().line == 4);
175 BOOST_TEST(*iter == '\n');
176 ++iter; // \r
177 BOOST_TEST(iter.get_position().line == 5);
178 BOOST_TEST(*iter == '\r');
179 ++iter; // end
180 BOOST_TEST(iter.get_position().line == 6);
181 BOOST_TEST(iter == end);
182 }
183
184 template <typename IterT>
CheckColumnCounting_Tab4(IterT iter)185 void CheckColumnCounting_Tab4(IterT iter)
186 {
187 IterT end;
188
189 // Don't call set_tabchars() here because
190 // default must be 3.
191 BOOST_TEST(*iter == '\t');
192 BOOST_TEST(iter.get_position().column == 1);
193 ++iter; // 0
194 BOOST_TEST(iter.get_position().column == 5);
195 ++iter; // 1
196 BOOST_TEST(iter.get_position().column == 6);
197 ++iter; // 2
198 BOOST_TEST(iter.get_position().column == 7);
199 ++iter; // 3
200 BOOST_TEST(iter.get_position().column == 8);
201 ++iter; // tab
202 BOOST_TEST(*iter == '\t');
203 BOOST_TEST(iter.get_position().column == 9);
204 ++iter; // 4
205 BOOST_TEST(iter.get_position().column == 13);
206 ++iter; // tab
207 BOOST_TEST(*iter == '\t');
208 BOOST_TEST(iter.get_position().column == 14);
209 ++iter; // 5
210 BOOST_TEST(iter.get_position().column == 17);
211 ++iter; // tab
212 BOOST_TEST(*iter == '\t');
213 BOOST_TEST(iter.get_position().column == 18);
214 ++iter; // end
215 BOOST_TEST(iter == end);
216 }
217
218 template <typename IterT>
CheckColumnCounting_Tab3(IterT iter)219 void CheckColumnCounting_Tab3(IterT iter)
220 {
221 IterT end;
222
223 iter.set_tabchars(3);
224
225 // Check also that tab settings propagates through
226 // assignment and copy construction
227 IterT iter2(iter);
228 IterT iter3; iter3 = iter2;
229
230 BOOST_TEST(*iter == '\t');
231 BOOST_TEST(iter.get_position().column == 1);
232 ++iter; // 0
233 ++iter2; ++iter3;
234 BOOST_TEST(iter.get_position().column == 4);
235 BOOST_TEST(iter2.get_position().column == 4);
236 BOOST_TEST(iter3.get_position().column == 4);
237 ++iter; // 1
238 BOOST_TEST(iter.get_position().column == 5);
239 ++iter; // 2
240 BOOST_TEST(iter.get_position().column == 6);
241 ++iter; // 3
242 BOOST_TEST(iter.get_position().column == 7);
243 ++iter; // tab
244 BOOST_TEST(*iter == '\t');
245 BOOST_TEST(iter.get_position().column == 8);
246 ++iter; // 4
247 BOOST_TEST(iter.get_position().column == 10);
248 ++iter; // tab
249 BOOST_TEST(*iter == '\t');
250 BOOST_TEST(iter.get_position().column == 11);
251 ++iter; // 5
252 BOOST_TEST(iter.get_position().column == 13);
253 ++iter; // tab
254 BOOST_TEST(*iter == '\t');
255 BOOST_TEST(iter.get_position().column == 14);
256 ++iter; // end
257 BOOST_TEST(iter == end);
258 }
259
260 const string line1 = "abcd";
261 const string line2 = "efgh";
262 const string linebuf = "\n" + line1 + "\n" + line2 + "\n";
263
264 template <typename IterT>
AssertIterString(IterT begin,IterT end,string s)265 void AssertIterString(IterT begin, IterT end, string s)
266 {
267 BOOST_TEST(string(begin, end) == s);
268 }
269
270 template <typename IterT>
CheckLineExtractionOne(IterT iter)271 void CheckLineExtractionOne(IterT iter)
272 {
273 IterT end;
274
275 // At the start, we are on a newline, which is an empty
276 // string
277 BOOST_TEST(iter.get_currentline() == string());
278 BOOST_TEST(
279 string(iter.get_currentline_begin(), iter.get_currentline_end())
280 == string());
281
282 ++iter; // a
283 ++iter; // b
284 ++iter; // c
285 BOOST_TEST(iter.get_currentline() == line1);
286 AssertIterString(
287 iter.get_currentline_begin(),
288 iter.get_currentline_end(),
289 line1);
290
291 ++iter; // d
292 ++iter; // newline
293 ++iter; // e
294
295 // check that copy construction and assignment do
296 // not interfere with get_currentline
297 IterT iter2(iter);
298 IterT iter3; iter3 = iter;
299 BOOST_TEST(iter2.get_currentline() == line2);
300 BOOST_TEST(iter3.get_currentline() == line2);
301 AssertIterString(
302 iter2.get_currentline_begin(),
303 iter2.get_currentline_end(),
304 line2);
305 AssertIterString(
306 iter3.get_currentline_begin(),
307 iter3.get_currentline_end(),
308 line2);
309
310 ++iter; // f
311 ++iter; // g
312 ++iter; // h
313 ++iter; // newline
314
315 // Check when the iterator is on a newline
316 BOOST_TEST(iter.get_currentline() == line2);
317 AssertIterString(
318 iter.get_currentline_begin(),
319 iter.get_currentline_end(),
320 line2);
321
322 ++iter;
323 BOOST_TEST(iter == end);
324 }
325
326
CheckLineExtraction(void)327 void CheckLineExtraction(void)
328 {
329 typedef string::const_iterator iter_t;
330
331 CheckLineExtractionOne(
332 position_iterator2<iter_t, file_position>
333 (linebuf.begin(), linebuf.end(), ""));
334
335 CheckLineExtractionOne(
336 position_iterator2<iter_t, file_position_without_column>
337 (linebuf.begin(), linebuf.end(), ""));
338 }
339
340 template <typename IterT>
CheckEmptySequence(void)341 void CheckEmptySequence(void)
342 {
343 typedef IterT iter_t;
344 char a[10];
345
346 // Check construction with empty sequence, and
347 // correct propagation of the information
348 iter_t iter(a,a, "");
349 iter_t iter2(iter);
350 iter_t iter3; iter3 = iter;
351
352 BOOST_TEST(iter == iter_t());
353 BOOST_TEST(iter2 == iter_t());
354 BOOST_TEST(iter3 == iter_t());
355 }
356
357 template <typename IterC, typename Iter>
CheckConstructors(void)358 void CheckConstructors(void)
359 {
360 char a[20];
361 std::string name = "abc";
362
363 file_position_without_column pos(name,1);
364 file_position posc(name,1,1);
365 typedef IterC iterc_t;
366 typedef Iter iter_t;
367
368 BOOST_TEST(iterc_t(a,a+20,name).get_position() == posc);
369 BOOST_TEST(iterc_t(a,a+20,name,1).get_position() == posc);
370 BOOST_TEST(iterc_t(a,a+20,name,1,1).get_position() == posc);
371 BOOST_TEST(iterc_t(a,a+20,posc).get_position() == posc);
372 BOOST_TEST(iter_t(a,a+20,name).get_position() == pos);
373 BOOST_TEST(iter_t(a,a+20,name,1).get_position() == pos);
374 BOOST_TEST(iter_t(a,a+20,pos).get_position() == pos);
375
376 // Check copy constructor and assignment. Notice that we want
377 // an implicit copy constructor.
378 iterc_t ic1(a,a+20,name);
379 iterc_t ic2 = ic1;
380 iterc_t ic3; ic3 = ic1;
381 BOOST_TEST(ic1 == ic2);
382 BOOST_TEST(ic1 == ic3);
383 BOOST_TEST(ic1.get_position() == ic2.get_position());
384 BOOST_TEST(ic1.get_position() == ic3.get_position());
385
386 iter_t i1(a,a+20,name);
387 iter_t i2 = i1;
388 iter_t i3; i3 = i1;
389 BOOST_TEST(i1 == i2);
390 BOOST_TEST(i1 == i3);
391 BOOST_TEST(i1.get_position() == i2.get_position());
392 BOOST_TEST(i1.get_position() == i3.get_position());
393
394 // Check construction with an empty sequence
395 CheckEmptySequence<iter_t>();
396 CheckEmptySequence<iterc_t>();
397 }
398
399 template <typename IterT>
CheckDistance(IterT begin)400 void CheckDistance(IterT begin)
401 {
402 IterT end;
403
404 std::size_t std_distance = std::distance(begin, end);
405
406 std::size_t manual_count = 0;
407 for(IterT it = begin; it != end; ++it)
408 ++manual_count;
409
410 BOOST_TEST(std_distance == manual_count);
411 }
412
413
414 ///////////////////////////////////////////////////////////////////////////////
415 } /* namespace test_impl */
416
417
CheckConstructors(void)418 void CheckConstructors(void)
419 {
420 test_impl::CheckConstructors
421 <
422 position_iterator<char*, file_position>,
423 position_iterator<char*, file_position_without_column>
424 >();
425
426 test_impl::CheckConstructors
427 <
428 position_iterator2<char*, file_position>,
429 position_iterator2<char*, file_position_without_column>
430 >();
431 }
432
CheckBasicFunctionality(void)433 void CheckBasicFunctionality(void)
434 {
435 const char* a = "0123456789";
436 typedef const char* iter_t;
437
438 test_impl::CheckIncrement(position_iterator<iter_t>(a, a+10, ""));
439 test_impl::CheckIncrement(position_iterator2<iter_t>(a, a+10, ""));
440 test_impl::CheckIncrement(position_iterator<iter_t, file_position_without_column>(a, a+10, ""));
441 test_impl::CheckIncrement(position_iterator2<iter_t, file_position_without_column>(a, a+10, ""));
442
443 const char* b = "\n0123\r\n4567\n89\n\r";
444
445 test_impl::CheckLineCounting(position_iterator<iter_t>(b, b+16, ""));
446 test_impl::CheckLineCounting(position_iterator2<iter_t>(b, b+16, ""));
447 test_impl::CheckLineCounting(position_iterator<iter_t, file_position_without_column>(b, b+16, ""));
448 test_impl::CheckLineCounting(position_iterator2<iter_t, file_position_without_column>(b, b+16, ""));
449 }
450
451
CheckColumnCounting(void)452 void CheckColumnCounting(void)
453 {
454 const char* a = "\t0123\t4\t5\t";
455 typedef const char* iter_t;
456
457 test_impl::CheckColumnCounting_Tab4(position_iterator<iter_t>(a, a+10, ""));
458 test_impl::CheckColumnCounting_Tab4(position_iterator2<iter_t>(a, a+10, ""));
459 test_impl::CheckColumnCounting_Tab3(position_iterator<iter_t>(a, a+10, ""));
460 test_impl::CheckColumnCounting_Tab3(position_iterator2<iter_t>(a, a+10, ""));
461 }
462
CheckLineExtraction(void)463 void CheckLineExtraction(void)
464 {
465 test_impl::CheckLineExtraction();
466 }
467
CheckDistance(void)468 void CheckDistance(void)
469 {
470 const char* b = "\n0123\r\n4567\n89\n\r";
471 typedef const char* iter_t;
472
473 test_impl::CheckDistance(position_iterator<iter_t>(b, b+15, ""));
474 test_impl::CheckDistance(position_iterator2<iter_t>(b, b+15, ""));
475 test_impl::CheckDistance(position_iterator<iter_t, file_position_without_column>(b, b+15, ""));
476 test_impl::CheckDistance(position_iterator2<iter_t, file_position_without_column>(b, b+15, ""));
477 }
478
479 ///////////////////////////////////////////////////////////////////////////////
480
481 namespace test_impl {
482
483 template <bool AsValue = false>
484 class check_singular_iterator
485 {
486 bool singular_;
487 int count_;
488
489 public:
490 typedef std::forward_iterator_tag iterator_category;
491 typedef int value_type;
492 typedef std::ptrdiff_t difference_type;
493 typedef int const* pointer;
494 typedef typename boost::mpl::if_c<AsValue, int, int const&>::type reference;
495
check_singular_iterator()496 check_singular_iterator() : singular_(true), count_(0) {}
check_singular_iterator(int x)497 explicit check_singular_iterator(int x) : singular_(false), count_(x) {}
498
operator *() const499 reference operator*() const {
500 BOOST_TEST(!singular_);
501 return count_;
502 }
503
operator ->() const504 pointer operator->() const {
505 BOOST_TEST(!singular_);
506 return &count_;
507 }
508
operator ++()509 check_singular_iterator& operator++() {
510 BOOST_TEST(count_ > 0);
511 --count_;
512 return *this;
513 }
514
operator ++(int)515 check_singular_iterator operator++(int) {
516 check_singular_iterator tmp(*this);
517 ++(*this);
518 return tmp;
519 }
520
operator ==(check_singular_iterator const & other) const521 bool operator==(check_singular_iterator const& other) const {
522 BOOST_TEST(!singular_ && !other.singular_);
523 return count_ == other.count_;
524 }
525
operator !=(check_singular_iterator const & other) const526 bool operator!=(check_singular_iterator const& other) const {
527 return !(*this == other);
528 }
529 };
530
531 template <typename CountIterator, typename Iterator>
CheckSingularImpl()532 void CheckSingularImpl()
533 {
534 CountIterator begin(Iterator(5), Iterator(0));
535 CountIterator end1(Iterator(0), Iterator(0));
536 CountIterator end2;
537
538 BOOST_TEST(begin == begin);
539 BOOST_TEST(begin != end1);
540 BOOST_TEST(begin != end2);
541
542 BOOST_TEST(end1 != begin);
543 BOOST_TEST(end1 == end1);
544 BOOST_TEST(end1 == end2);
545
546 BOOST_TEST(end2 != begin);
547 BOOST_TEST(end2 == end1);
548 BOOST_TEST(end2 == end2);
549
550 BOOST_TEST(std::distance(begin, begin) == 0);
551 BOOST_TEST(std::distance(begin, end1) == 5);
552 BOOST_TEST(std::distance(begin, end2) == 5);
553
554 BOOST_TEST(std::distance(end1, end1) == 0);
555 BOOST_TEST(std::distance(end1, end2) == 0);
556
557 BOOST_TEST(std::distance(end2, end1) == 0);
558 BOOST_TEST(std::distance(end2, end2) == 0);
559
560 BOOST_TEST(*begin == 5);
561 }
562
563 template <typename PositionT>
CheckSingular()564 void CheckSingular()
565 {
566 {
567 typedef check_singular_iterator<false> interator_type;
568 CheckSingularImpl<position_iterator<interator_type, PositionT>, interator_type>();
569 CheckSingularImpl<position_iterator2<interator_type, PositionT>, interator_type>();
570 }
571 {
572 typedef check_singular_iterator<true> interator_type;
573 CheckSingularImpl<position_iterator<interator_type, PositionT>, interator_type>();
574 CheckSingularImpl<position_iterator2<interator_type, PositionT>, interator_type>();
575 }
576 }
577 }
578
CheckSingular()579 void CheckSingular()
580 {
581 test_impl::CheckSingular<file_position>();
582 test_impl::CheckSingular<file_position_without_column>();
583 }
584