text: /*
  Copyright 2003 Daryle Walker
  
  Copyright 2019 Glen Joseph Fernandes
  (glenjofe@gmail.com)
  
  Distributed under the Boost Software License, Version 1.0.
  (http://www.boost.org/LICENSE_1_0.txt)
  */
  #include <boost/io/ios_state.hpp>
  #include <boost/core/lightweight_test.hpp>
  #include <boost/config.hpp>
  #include <iomanip>
  #include <ios>
  #include <iostream>
  #include <istream>
  #include <locale>
  #if defined(BOOST_GCC) || (defined(BOOST_CLANG) && defined(BOOST_GNU_STDLIB))
  #include <stdexcept>
  #endif
  #include <sstream>
  #include <cstddef>
  
  class backward_bool_names
      : public std::numpunct<char> {
      typedef std::numpunct<char> base_type;
  
  public:
      explicit backward_bool_names(std::size_t refs = 0)
          : base_type(refs) { }
  
  protected:
      ~backward_bool_names() { }
  
      base_type::string_type do_truename() const {
          return "eurt";
      }
  
      base_type::string_type do_falsename() const {
          return "eslaf";
      }
  };
  
  void
  ios_flags_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      {
          boost::io::ios_flags_saver ifs(ss);
          BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
          ss << std::noskipws << std::fixed << std::boolalpha;
          BOOST_TEST_EQ(std::ios_base::boolalpha |
              std::ios_base::dec |
              std::ios_base::fixed, ss.flags());
      }
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      {
          boost::io::ios_flags_saver ifs(ss,
              std::ios_base::showbase | std::ios_base::internal);
          BOOST_TEST_EQ(std::ios_base::showbase |
              std::ios_base::internal, ss.flags());
          ss << std::setiosflags(std::ios_base::unitbuf);
          BOOST_TEST_EQ(std::ios_base::showbase |
              std::ios_base::internal |
              std::ios_base::unitbuf, ss.flags());
      }
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
  }
  
  void
  ios_precision_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(6, ss.precision());
      {
          boost::io::ios_precision_saver ips(ss);
          BOOST_TEST_EQ(6, ss.precision());
          ss << std::setprecision(4);
          BOOST_TEST_EQ(4, ss.precision());
      }
      BOOST_TEST_EQ(6, ss.precision());
      {
          boost::io::ios_precision_saver ips(ss, 8);
          BOOST_TEST_EQ(8, ss.precision());
          ss << std::setprecision(10);
          BOOST_TEST_EQ(10, ss.precision());
      }
      BOOST_TEST_EQ(6, ss.precision());
  }
  
  void
  ios_width_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(0, ss.width());
      {
          boost::io::ios_width_saver iws(ss);
          BOOST_TEST_EQ(0, ss.width());
          ss << std::setw(4);
          BOOST_TEST_EQ(4, ss.width());
      }
      BOOST_TEST_EQ(0, ss.width());
      {
          boost::io::ios_width_saver iws(ss, 8);
          BOOST_TEST_EQ(8, ss.width());
          ss << std::setw(10);
          BOOST_TEST_EQ(10, ss.width());
      }
      BOOST_TEST_EQ(0, ss.width());
  }
  
  void
  ios_iostate_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
      BOOST_TEST(ss.good());
      {
          boost::io::ios_iostate_saver iis(ss);
          char c;
          BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
          BOOST_TEST(ss.good());
          ss >> c;
          BOOST_TEST_EQ(std::ios_base::eofbit | std::ios_base::failbit,
              ss.rdstate());
          BOOST_TEST(ss.eof());
          BOOST_TEST(ss.fail());
          BOOST_TEST(!ss.bad());
      }
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
      BOOST_TEST(ss.good());
      {
          boost::io::ios_iostate_saver iis(ss, std::ios_base::eofbit);
          BOOST_TEST_EQ(std::ios_base::eofbit, ss.rdstate());
          BOOST_TEST(ss.eof());
          ss.setstate(std::ios_base::badbit);
          BOOST_TEST_EQ(std::ios_base::eofbit | std::ios_base::badbit,
              ss.rdstate());
          BOOST_TEST(ss.eof());
          BOOST_TEST(ss.fail());
          BOOST_TEST(ss.bad());
      }
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
      BOOST_TEST(ss.good());
  }
  
  void
  ios_exception_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
      {
          boost::io::ios_exception_saver ies(ss);
          BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
          ss.exceptions(std::ios_base::failbit);
          BOOST_TEST_EQ(std::ios_base::failbit, ss.exceptions());
          {
              boost::io::ios_iostate_saver iis(ss);
              ss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
              char c;
  #if defined(BOOST_GCC) || (defined(BOOST_CLANG) && defined(BOOST_GNU_STDLIB))
              BOOST_TEST_THROWS(ss >> c, std::exception);
  #else
              BOOST_TEST_THROWS(ss >> c, std::ios_base::failure);
  #endif
          }
      }
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
      {
          boost::io::ios_exception_saver ies(ss, std::ios_base::eofbit);
          BOOST_TEST_EQ(std::ios_base::eofbit, ss.exceptions());
          ss.exceptions(std::ios_base::badbit);
          BOOST_TEST_EQ(std::ios_base::badbit, ss.exceptions());
          {
              boost::io::ios_iostate_saver iis(ss);
              char c;
              BOOST_TEST_NOT(ss >> c);
          }
      }
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
  }
  
  void
  ios_tie_saver_unit_test()
  {
      BOOST_TEST(NULL == std::cout.tie());
      {
          boost::io::ios_tie_saver its(std::cout);
          BOOST_TEST(NULL == std::cout.tie());
          std::cout.tie(&std::clog);
          BOOST_TEST_EQ(&std::clog, std::cout.tie());
      }
      BOOST_TEST(NULL == std::cout.tie());
      {
          boost::io::ios_tie_saver its(std::cout, &std::clog);
          BOOST_TEST_EQ(&std::clog, std::cout.tie());
          std::cout.tie(&std::cerr);
          BOOST_TEST_EQ(&std::cerr, std::cout.tie());
      }
      BOOST_TEST(NULL == std::cout.tie());
  }
  
  void
  ios_rdbuf_saver_unit_test()
  {
      std::iostream s(NULL);
      BOOST_TEST(NULL == s.rdbuf());
      {
          std::stringbuf sb;
          boost::io::ios_rdbuf_saver irs(s);
          BOOST_TEST(NULL == s.rdbuf());
          s.rdbuf(&sb);
          BOOST_TEST_EQ(&sb, s.rdbuf());
      }
      BOOST_TEST(NULL == s.rdbuf());
      {
          std::stringbuf sb1, sb2("Hi there");
          boost::io::ios_rdbuf_saver irs(s, &sb1);
          BOOST_TEST_EQ(&sb1, s.rdbuf());
          s.rdbuf(&sb2);
          BOOST_TEST_EQ(&sb2, s.rdbuf());
      }
      BOOST_TEST(NULL == s.rdbuf());
  }
  
  void
  ios_fill_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(' ',  ss.fill());
      {
          boost::io::ios_fill_saver ifs(ss);
          BOOST_TEST_EQ(' ', ss.fill());
          ss.fill('x');
          BOOST_TEST_EQ('x', ss.fill());
      }
      BOOST_TEST_EQ(' ', ss.fill());
      {
          boost::io::ios_fill_saver ifs(ss, '3');
          BOOST_TEST_EQ('3', ss.fill());
          ss.fill('+');
          BOOST_TEST_EQ('+', ss.fill());
      }
      BOOST_TEST_EQ(' ', ss.fill());
  }
  
  void
  ios_locale_saver_unit_test()
  {
      typedef std::numpunct<char> npc_type;
      std::stringstream ss;
      BOOST_TEST(std::locale() == ss.getloc());
      BOOST_TEST(!std::has_facet<npc_type>(ss.getloc()) ||
          !dynamic_cast<const backward_bool_names*>(&
          std::use_facet<npc_type>(ss.getloc())));
      {
          boost::io::ios_locale_saver ils(ss);
          BOOST_TEST(std::locale() == ss.getloc());
          ss.imbue(std::locale::classic());
          BOOST_TEST(std::locale::classic() == ss.getloc());
      }
      BOOST_TEST(std::locale() == ss.getloc());
      BOOST_TEST(!std::has_facet<npc_type>(ss.getloc()) ||
          !dynamic_cast<const backward_bool_names*>(&
          std::use_facet<npc_type>(ss.getloc())));
      {
          boost::io::ios_locale_saver ils(ss, std::locale::classic());
          BOOST_TEST(std::locale::classic() == ss.getloc());
          BOOST_TEST(!std::has_facet<npc_type>(ss.getloc()) ||
              !dynamic_cast<const backward_bool_names*>(&
              std::use_facet<npc_type>(ss.getloc())));
          ss.imbue(std::locale(std::locale::classic(), new backward_bool_names));
          BOOST_TEST(std::locale::classic() != ss.getloc());
          BOOST_TEST(std::has_facet<npc_type>(ss.getloc()) &&
              dynamic_cast<const backward_bool_names*>(&
              std::use_facet<npc_type>(ss.getloc())));
      }
      BOOST_TEST(std::locale() == ss.getloc());
      BOOST_TEST(!std::has_facet<npc_type>(ss.getloc()) ||
          !dynamic_cast<const backward_bool_names*>(&
          std::use_facet<npc_type>(ss.getloc())));
  }
  
  void
  ios_iword_saver_unit_test(int index)
  {
      std::stringstream ss;
      BOOST_TEST_EQ(0, ss.iword(index));
      {
          boost::io::ios_iword_saver iis(ss, index);
          BOOST_TEST_EQ(0, ss.iword(index));
          ss.iword(index) = 6;
          BOOST_TEST_EQ(6, ss.iword(index));
      }
      BOOST_TEST_EQ(0, ss.iword(index));
      {
          boost::io::ios_iword_saver iis(ss, index, 100);
          BOOST_TEST_EQ(100, ss.iword(index));
          ss.iword(index) = -2000;
          BOOST_TEST_EQ(-2000, ss.iword(index));
      }
      BOOST_TEST_EQ(0, ss.iword(index));
  }
  
  void
  ios_pword_saver_unit_test(int index)
  {
      std::stringstream ss;
      BOOST_TEST(NULL == ss.pword(index));
      {
          boost::io::ios_pword_saver ips(ss, index);
          BOOST_TEST(NULL == ss.pword(index));
          ss.pword(index) = &ss;
          BOOST_TEST_EQ(&ss, ss.pword(index));
      }
      BOOST_TEST(NULL == ss.pword(index));
      {
          boost::io::ios_pword_saver ips(ss, index, ss.rdbuf());
          BOOST_TEST_EQ(ss.rdbuf(), ss.pword(index));
          ss.pword(index) = &ss;
          BOOST_TEST_EQ(&ss, ss.pword(index));
      }
      BOOST_TEST(NULL == ss.pword(index));
  }
  
  void
  ios_base_all_saver_unit_test()
  {
      std::stringstream ss;
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      BOOST_TEST_EQ(6, ss.precision());
      BOOST_TEST_EQ(0, ss.width());
      {
          boost::io::ios_base_all_saver ibas(ss);
          BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
          BOOST_TEST_EQ(6, ss.precision());
          BOOST_TEST_EQ(0, ss.width());
          ss << std::hex << std::unitbuf << std::setprecision(5) << std::setw(7);
          BOOST_TEST_EQ(std::ios_base::unitbuf |
              std::ios_base::hex |
              std::ios_base::skipws, ss.flags());
          BOOST_TEST_EQ(5, ss.precision());
          BOOST_TEST_EQ(7, ss.width());
      }
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      BOOST_TEST_EQ(6, ss.precision());
      BOOST_TEST_EQ(0, ss.width());
  }
  
  void
  ios_all_saver_unit_test()
  {
      typedef std::numpunct<char> npc_type;
      std::stringbuf sb;
      std::iostream ss(&sb);
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      BOOST_TEST_EQ(6, ss.precision());
      BOOST_TEST_EQ(0, ss.width());
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
      BOOST_TEST(ss.good());
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
      BOOST_TEST(NULL == ss.tie());
      BOOST_TEST(&sb == ss.rdbuf());
      BOOST_TEST_EQ(' ',  ss.fill());
      BOOST_TEST(std::locale() == ss.getloc());
      {
          boost::io::ios_all_saver ias(ss);
          BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
          BOOST_TEST_EQ(6, ss.precision());
          BOOST_TEST_EQ(0, ss.width());
          BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
          BOOST_TEST(ss.good());
          BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
          BOOST_TEST(NULL == ss.tie());
          BOOST_TEST(&sb == ss.rdbuf());
          BOOST_TEST_EQ(' ', ss.fill());
          BOOST_TEST(std::locale() == ss.getloc());
          ss << std::oct << std::showpos << std::noskipws;
          BOOST_TEST_EQ(std::ios_base::showpos | std::ios_base::oct, ss.flags());
          ss << std::setprecision(3);
          BOOST_TEST_EQ(3, ss.precision());
          ss << std::setw(9);
          BOOST_TEST_EQ(9, ss.width());
          ss.setstate(std::ios_base::eofbit);
          BOOST_TEST_EQ(std::ios_base::eofbit, ss.rdstate());
          BOOST_TEST(ss.eof());
          ss.exceptions(std::ios_base::failbit);
          BOOST_TEST_EQ(std::ios_base::failbit, ss.exceptions());
          {
              boost::io::ios_iostate_saver iis(ss);
              ss.exceptions(std::ios_base::failbit | std::ios_base::badbit);
              char c;
  #if defined(BOOST_GCC) || (defined(BOOST_CLANG) && defined(BOOST_GNU_STDLIB))
              BOOST_TEST_THROWS(ss >> c, std::exception);
  #else
              BOOST_TEST_THROWS(ss >> c, std::ios_base::failure);
  #endif
          }
          ss.tie(&std::clog);
          BOOST_TEST_EQ(&std::clog, ss.tie());
          ss.rdbuf(std::cerr.rdbuf());
          BOOST_TEST_EQ(std::cerr.rdbuf(), ss.rdbuf());
          ss << std::setfill('x');
          BOOST_TEST_EQ('x', ss.fill());
          ss.imbue(std::locale(std::locale::classic(), new backward_bool_names));
          BOOST_TEST(std::locale() != ss.getloc());
          BOOST_TEST(std::has_facet<npc_type>(ss.getloc()) &&
              dynamic_cast<const backward_bool_names*>(&
              std::use_facet<npc_type>(ss.getloc())));
      }
      BOOST_TEST_EQ(std::ios_base::skipws | std::ios_base::dec, ss.flags());
      BOOST_TEST_EQ(6, ss.precision());
      BOOST_TEST_EQ(0, ss.width());
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.rdstate());
      BOOST_TEST(ss.good());
      BOOST_TEST_EQ(std::ios_base::goodbit, ss.exceptions());
      BOOST_TEST(NULL == ss.tie());
      BOOST_TEST(&sb == ss.rdbuf());
      BOOST_TEST_EQ(' ', ss.fill());
      BOOST_TEST(std::locale() == ss.getloc());
  }
  
  void
  ios_word_saver_unit_test(int index)
  {
      std::stringstream ss;
      BOOST_TEST_EQ(0, ss.iword(index));
      BOOST_TEST(NULL == ss.pword(index));
      {
          boost::io::ios_all_word_saver iaws(ss, index);
          BOOST_TEST_EQ(0, ss.iword(index));
          BOOST_TEST(NULL == ss.pword(index));
          ss.iword(index) = -11;
          ss.pword(index) = ss.rdbuf();
          BOOST_TEST_EQ(-11, ss.iword(index));
          BOOST_TEST_EQ(ss.rdbuf(), ss.pword(index));
      }
      BOOST_TEST_EQ(0, ss.iword(index));
      BOOST_TEST(NULL == ss.pword(index));
  }
  
  int main()
  {
      int index = std::ios_base::xalloc();
      ios_flags_saver_unit_test();
      ios_precision_saver_unit_test();
      ios_width_saver_unit_test();
      ios_iostate_saver_unit_test();
      ios_exception_saver_unit_test();
      ios_tie_saver_unit_test();
      ios_rdbuf_saver_unit_test();
      ios_fill_saver_unit_test();
      ios_locale_saver_unit_test();
      ios_iword_saver_unit_test(index);
      ios_pword_saver_unit_test(index);
      ios_base_all_saver_unit_test();
      ios_all_saver_unit_test();
      ios_word_saver_unit_test(index);
      return boost::report_errors();
  }
  