• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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