text: /*=============================================================================
      Copyright (c) 2001-2003 Daniel Nuffer
      http://spirit.sourceforge.net/
  
      Use, modification and distribution is subject to the Boost Software
      License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
      http://www.boost.org/LICENSE_1_0.txt)
  =============================================================================*/
  #include <boost/spirit/include/classic_multi_pass.hpp>
  #include <boost/scoped_ptr.hpp>
  #include <iterator>
  #include <string>
  #include <boost/detail/lightweight_test.hpp>
  #include "impl/sstream.hpp"
  
  using namespace std;
  using namespace BOOST_SPIRIT_CLASSIC_NS;
  
  sstream_t res;
  
  typedef multi_pass<istream_iterator<char> > default_multi_pass_t;
  
  typedef look_ahead<istream_iterator<char>, 6> fixed_multi_pass_t;
  
  typedef multi_pass<
      istream_iterator<char>,
      multi_pass_policies::input_iterator,
      multi_pass_policies::first_owner,
      multi_pass_policies::buf_id_check,
      multi_pass_policies::std_deque
  > first_owner_multi_pass_t;
  
  
  // a functor to test out the functor_multi_pass
  class my_functor
  {
      public:
          typedef char result_type;
          my_functor()
              : c('A')
          {}
  
          char operator()()
          {
              if (c == 'M')
                  return eof;
              else
                  return c++;
          }
  
          static result_type eof;
      private:
          char c;
  };
  
  my_functor::result_type my_functor::eof = '\0';
  
  typedef multi_pass<
      my_functor,
      multi_pass_policies::functor_input,
      multi_pass_policies::first_owner,
      multi_pass_policies::no_check,
      multi_pass_policies::std_deque
  > functor_multi_pass_t;
  
  void test_default_multi_pass()
  {
      res << "-*= test_default_multi_pass =*-\n";
      istream_iterator<char> end;
      boost::scoped_ptr<default_multi_pass_t> mpend(new default_multi_pass_t(end));
  
      {
          sstream_t ss;
          ss << "test string";
  
          istream_iterator<char> a(ss);
          boost::scoped_ptr<default_multi_pass_t> mp1(new default_multi_pass_t(a));
  
          while (*mp1 != *mpend)
          {
              res << *((*mp1)++);
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(b));
          boost::scoped_ptr<default_multi_pass_t> mp3(new default_multi_pass_t(b));
          *mp3 = *mp2;
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<default_multi_pass_t> mp1(new default_multi_pass_t(a));
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(*mp1));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(b));
          boost::scoped_ptr<default_multi_pass_t> mp3(new default_multi_pass_t(b));
          *mp3 = *mp2;
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
          ++*mp2;
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<default_multi_pass_t> mp1(new default_multi_pass_t(a));
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(*mp1));
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mp1)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<default_multi_pass_t> mp1(new default_multi_pass_t(a));
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(a));
          BOOST_TEST(*mp1 != *mp2);
          ++*mp1;
          BOOST_TEST(*mp1 != *mp2);
  
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<default_multi_pass_t> mp2(new default_multi_pass_t(b));
          boost::scoped_ptr<default_multi_pass_t> mp3(new default_multi_pass_t(b));
          *mp3 = *mp2;
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp2->clear_queue();
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          try
          {
              res << **mp3; // this should throw illegal_backtracking
              BOOST_TEST(0);
          }
          catch (const BOOST_SPIRIT_CLASSIC_NS::multi_pass_policies::illegal_backtracking& /*e*/)
          {
          }
          res << endl;
      }
  
  
  }
  
  void test_fixed_multi_pass()
  {
      res << "-*= test_fixed_multi_pass =*-\n";
      istream_iterator<char> end;
      boost::scoped_ptr<fixed_multi_pass_t> mpend(new fixed_multi_pass_t(end));
  
      {
          sstream_t ss;
          ss << "test string";
  
          istream_iterator<char> a(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp1(new fixed_multi_pass_t(a));
  
          while (*mp1 != *mpend)
          {
              res << *((*mp1)++);
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp2(new fixed_multi_pass_t(b));
          boost::scoped_ptr<fixed_multi_pass_t> mp3(new fixed_multi_pass_t(*mp2));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp1(new fixed_multi_pass_t(a));
          boost::scoped_ptr<fixed_multi_pass_t> mp2(new fixed_multi_pass_t(*mp1));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp2(new fixed_multi_pass_t(b));
          boost::scoped_ptr<fixed_multi_pass_t> mp3(new fixed_multi_pass_t(*mp2));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
          ++*mp2;
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp1(new fixed_multi_pass_t(a));
          boost::scoped_ptr<fixed_multi_pass_t> mp2(new fixed_multi_pass_t(*mp1));
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mp1)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<fixed_multi_pass_t> mp1(new fixed_multi_pass_t(a));
          boost::scoped_ptr<fixed_multi_pass_t> mp2(new fixed_multi_pass_t(a));
          BOOST_TEST(*mp1 != *mp2);
          ++*mp1;
          BOOST_TEST(*mp1 != *mp2);
  
      }
  
  }
  
  void test_first_owner_multi_pass()
  {
      res << "-*= test_first_owner_multi_pass =*-\n";
      istream_iterator<char> end;
      boost::scoped_ptr<first_owner_multi_pass_t> mpend(new first_owner_multi_pass_t(end));
  
      {
          sstream_t ss;
          ss << "test string";
  
          istream_iterator<char> a(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp1(new first_owner_multi_pass_t(a));
  
          while (*mp1 != *mpend)
          {
              res << *((*mp1)++);
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(b));
          boost::scoped_ptr<first_owner_multi_pass_t> mp3(new first_owner_multi_pass_t(*mp2));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp1(new first_owner_multi_pass_t(a));
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(*mp1));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(b));
          boost::scoped_ptr<first_owner_multi_pass_t> mp3(new first_owner_multi_pass_t(*mp2));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp3.reset();
          ++*mp2;
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp1(new first_owner_multi_pass_t(a));
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(*mp1));
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          for (int i = 0; i < 4; ++i)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mp1)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          while (*mp1 != *mpend)
          {
              res << **mp1;
              ++*mp1;
          }
  
          BOOST_TEST(*mp1 != *mp2);
          BOOST_TEST(*mp1 > *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp2 < *mp1);
          BOOST_TEST(*mp2 <= *mp1);
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          BOOST_TEST(*mp1 == *mp2);
          BOOST_TEST(*mp1 >= *mp2);
          BOOST_TEST(*mp1 <= *mp2);
          res << endl;
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> a(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp1(new first_owner_multi_pass_t(a));
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(a));
          BOOST_TEST(*mp1 != *mp2);
          ++*mp1;
          BOOST_TEST(*mp1 != *mp2);
  
      }
  
      {
          sstream_t ss;
          ss << "test string";
          istream_iterator<char> b(ss);
          boost::scoped_ptr<first_owner_multi_pass_t> mp2(new first_owner_multi_pass_t(b));
          boost::scoped_ptr<first_owner_multi_pass_t> mp3(new first_owner_multi_pass_t(*mp2));
  
          for (int i = 0; i < 4; ++i)
          {
              res << **mp2;
              ++*mp2;
          }
  
          mp2->clear_queue();
  
          while (*mp2 != *mpend)
          {
              res << **mp2;
              ++*mp2;
          }
  
          try
          {
              res << **mp3; // this should throw illegal_backtracking
              BOOST_TEST(0);
          }
          catch (const BOOST_SPIRIT_CLASSIC_NS::multi_pass_policies::illegal_backtracking& /*e*/)
          {
          }
          res << endl;
      }
  
  }
  
  
  void test_functor_multi_pass()
  {
      res << "-*= test_functor_multi_pass =*-\n";
      functor_multi_pass_t mpend;
  
      {
          functor_multi_pass_t mp1 = functor_multi_pass_t(my_functor());
  
          while (mp1 != mpend)
          {
              res << *(mp1++);
          }
  
          res << endl;
      }
  
      {
          functor_multi_pass_t mp1 = functor_multi_pass_t(my_functor());
          functor_multi_pass_t mp2 = functor_multi_pass_t(mp1);
  
          for (int i = 0; i < 4; ++i)
          {
              res << *mp1;
              ++mp1;
          }
  
          while (mp2 != mpend)
          {
              res << *mp2;
              ++mp2;
          }
  
          while (mp1 != mpend)
          {
              res << *mp1;
              ++mp1;
          }
  
          res << endl;
      }
  
      {
          functor_multi_pass_t mp1 = functor_multi_pass_t(my_functor());
          functor_multi_pass_t mp2 = functor_multi_pass_t(mp1);
  
          BOOST_TEST(mp1 == mp2);
          BOOST_TEST(mp1 >= mp2);
          BOOST_TEST(mp1 <= mp2);
          for (int i = 0; i < 4; ++i)
          {
              res << *mp1;
              ++mp1;
          }
  
          BOOST_TEST(mp1 != mp2);
          BOOST_TEST(mp1 > mp2);
          BOOST_TEST(mp1 >= mp2);
          BOOST_TEST(mp2 < mp1);
          BOOST_TEST(mp2 <= mp1);
          while (mp2 != mp1)
          {
              res << *mp2;
              ++mp2;
          }
  
          BOOST_TEST(mp1 == mp2);
          BOOST_TEST(mp1 >= mp2);
          BOOST_TEST(mp1 <= mp2);
          while (mp1 != mpend)
          {
              res << *mp1;
              ++mp1;
          }
  
          BOOST_TEST(mp1 != mp2);
          BOOST_TEST(mp1 > mp2);
          BOOST_TEST(mp1 >= mp2);
          BOOST_TEST(mp2 < mp1);
          BOOST_TEST(mp2 <= mp1);
          while (mp2 != mpend)
          {
              res << *mp2;
              ++mp2;
          }
  
          BOOST_TEST(mp1 == mp2);
          BOOST_TEST(mp1 >= mp2);
          BOOST_TEST(mp1 <= mp2);
          res << endl;
      }
  
      {
          functor_multi_pass_t mp1 = functor_multi_pass_t(my_functor());
          functor_multi_pass_t mp2 = functor_multi_pass_t(my_functor());
          BOOST_TEST(mp1 != mp2);
          ++mp1;
          BOOST_TEST(mp1 != mp2);
  
      }
  }
  
  int main(int, char**)
  {
  
      test_default_multi_pass();
      test_fixed_multi_pass();
      test_first_owner_multi_pass();
      test_functor_multi_pass();
  
      BOOST_TEST(getstring(res) == "-*= test_default_multi_pass =*-\n"
              "teststring\n"
              "teststring\n"
              "testteststringstring\n"
              "testtring\n"
              "testteststringstring\n"
              "teststring\n"
              "-*= test_fixed_multi_pass =*-\n"
              "teststring\n"
              "teststring\n"
              "testteststringstring\n"
              "testtring\n"
              "testteststringstring\n"
              "-*= test_first_owner_multi_pass =*-\n"
              "teststring\n"
              "teststring\n"
              "testteststringstring\n"
              "testtring\n"
              "testteststringstring\n"
              "teststring\n"
              "-*= test_functor_multi_pass =*-\n"
              "ABCDEFGHIJKL\n"
              "ABCDABCDEFGHIJKLEFGHIJKL\n"
              "ABCDABCDEFGHIJKLEFGHIJKL\n");
  
      return boost::report_errors();
  }
  