text: //  Unit test for boost::lexical_cast.
  //
  //  See http://www.boost.org for most recent version, including documentation.
  //
  //  Copyright Antony Polukhin, 2011-2012.
  //
  //  Distributed under 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/config.hpp>
  #include <boost/test/unit_test.hpp>
  
  #include <boost/lexical_cast.hpp>
  
  #include <iostream>
  
  
  ///////////////////////// char streamable classes ///////////////////////////////////////////
  
  struct streamable_easy { enum ENU {value = 0}; };
  std::ostream& operator << (std::ostream& ostr, const streamable_easy&) {
      return ostr << streamable_easy::value;
  }
  std::istream& operator >> (std::istream& istr, const streamable_easy&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_easy::value);
      return istr;
  }
  
  struct streamable_medium { enum ENU {value = 1}; };
  template <class CharT>
  typename boost::enable_if<boost::is_same<CharT, char>, std::basic_ostream<CharT>&>::type 
  operator << (std::basic_ostream<CharT>& ostr, const streamable_medium&) {
      return ostr << streamable_medium::value;
  }
  template <class CharT>
  typename boost::enable_if<boost::is_same<CharT, char>, std::basic_istream<CharT>&>::type 
  operator >> (std::basic_istream<CharT>& istr, const streamable_medium&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_medium::value);
      return istr;
  }
  
  struct streamable_hard { enum ENU {value = 2}; };
  template <class CharT, class TraitsT>
  typename boost::enable_if<boost::is_same<CharT, char>, std::basic_ostream<CharT, TraitsT>&>::type 
  operator << (std::basic_ostream<CharT, TraitsT>& ostr, const streamable_hard&) {
      return ostr << streamable_hard::value;
  }
  template <class CharT, class TraitsT>
  typename boost::enable_if<boost::is_same<CharT, char>, std::basic_istream<CharT, TraitsT>&>::type 
  operator >> (std::basic_istream<CharT, TraitsT>& istr, const streamable_hard&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_hard::value);
      return istr;
  }
  
  struct streamable_hard2 { enum ENU {value = 3}; };
  template <class TraitsT>
  std::basic_ostream<char, TraitsT>& operator << (std::basic_ostream<char, TraitsT>& ostr, const streamable_hard2&) {
      return ostr << streamable_hard2::value;
  }
  template <class TraitsT>
  std::basic_istream<char, TraitsT>& operator >> (std::basic_istream<char, TraitsT>& istr, const streamable_hard2&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_hard2::value);
      return istr;
  }
  
  
  ///////////////////////// wchar_t streamable classes ///////////////////////////////////////////
  
  struct wstreamable_easy { enum ENU {value = 4}; };
  std::wostream& operator << (std::wostream& ostr, const wstreamable_easy&) {
      return ostr << wstreamable_easy::value;
  }
  std::wistream& operator >> (std::wistream& istr, const wstreamable_easy&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_easy::value);
      return istr;
  }
  
  struct wstreamable_medium { enum ENU {value = 5}; };
  template <class CharT>
  typename boost::enable_if<boost::is_same<CharT, wchar_t>, std::basic_ostream<CharT>& >::type 
  operator << (std::basic_ostream<CharT>& ostr, const wstreamable_medium&) {
      return ostr << wstreamable_medium::value;
  }
  template <class CharT>
  typename boost::enable_if<boost::is_same<CharT, wchar_t>, std::basic_istream<CharT>& >::type 
  operator >> (std::basic_istream<CharT>& istr, const wstreamable_medium&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_medium::value);
      return istr;
  }
  
  struct wstreamable_hard { enum ENU {value = 6}; };
  template <class CharT, class TraitsT>
  typename boost::enable_if<boost::is_same<CharT, wchar_t>, std::basic_ostream<CharT, TraitsT>&>::type 
  operator << (std::basic_ostream<CharT, TraitsT>& ostr, const wstreamable_hard&) {
      return ostr << wstreamable_hard::value;
  }
  template <class CharT, class TraitsT>
  typename boost::enable_if<boost::is_same<CharT, wchar_t>, std::basic_istream<CharT, TraitsT>&>::type 
  operator >> (std::basic_istream<CharT, TraitsT>& istr, const wstreamable_hard&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_hard::value);
      return istr;
  }
  
  struct wstreamable_hard2 { enum ENU {value = 7}; };
  template <class TraitsT>
  std::basic_ostream<wchar_t, TraitsT>& operator << (std::basic_ostream<wchar_t, TraitsT>& ostr, const wstreamable_hard2&) {
      return ostr << wstreamable_hard2::value;
  }
  template <class TraitsT>
  std::basic_istream<wchar_t, TraitsT>& operator >> (std::basic_istream<wchar_t, TraitsT>& istr, const wstreamable_hard2&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_hard2::value);
      return istr;
  }
  
  ///////////////////////// char and wchar_t streamable classes ///////////////////////////////////////////
  
  
  struct bistreamable_easy { enum ENU {value = 8}; };
  std::ostream& operator << (std::ostream& ostr, const bistreamable_easy&) {
      return ostr << bistreamable_easy::value;
  }
  std::istream& operator >> (std::istream& istr, const bistreamable_easy&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_easy::value);
      return istr;
  }
  
  std::wostream& operator << (std::wostream& ostr, const bistreamable_easy&) {
      return ostr << bistreamable_easy::value + 100;
  }
  std::wistream& operator >> (std::wistream& istr, const bistreamable_easy&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_easy::value + 100);
      return istr;
  }
  
  struct bistreamable_medium { enum ENU {value = 9}; };
  template <class CharT>
  std::basic_ostream<CharT>& operator << (std::basic_ostream<CharT>& ostr, const bistreamable_medium&) {
      return ostr << bistreamable_medium::value + (sizeof(CharT) == 1 ? 0 : 100);
  }
  template <class CharT>
  std::basic_istream<CharT>& operator >> (std::basic_istream<CharT>& istr, const bistreamable_medium&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_medium::value + (sizeof(CharT) == 1 ? 0 : 100));
      return istr;
  }
  
  struct bistreamable_hard { enum ENU {value = 10}; };
  template <class CharT, class TraitsT>
  std::basic_ostream<CharT, TraitsT>& operator << (std::basic_ostream<CharT, TraitsT>& ostr, const bistreamable_hard&) {
      return ostr << bistreamable_hard::value + (sizeof(CharT) == 1 ? 0 : 100);
  }
  template <class CharT, class TraitsT>
  std::basic_istream<CharT, TraitsT>& operator >> (std::basic_istream<CharT, TraitsT>& istr, const bistreamable_hard&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard::value + (sizeof(CharT) == 1 ? 0 : 100));
      return istr;
  }
  
  struct bistreamable_hard2 { enum ENU {value = 11}; };
  template <class TraitsT>
  std::basic_ostream<char, TraitsT>& operator << (std::basic_ostream<char, TraitsT>& ostr, const bistreamable_hard2&) {
      return ostr << bistreamable_hard2::value;
  }
  template <class TraitsT>
  std::basic_istream<char, TraitsT>& operator >> (std::basic_istream<char, TraitsT>& istr, const bistreamable_hard2&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard2::value);
      return istr;
  }
  
  template <class TraitsT>
  std::basic_ostream<wchar_t, TraitsT>& operator << (std::basic_ostream<wchar_t, TraitsT>& ostr, const bistreamable_hard2&) {
      return ostr << bistreamable_hard2::value + 100;
  }
  template <class TraitsT>
  std::basic_istream<wchar_t, TraitsT>& operator >> (std::basic_istream<wchar_t, TraitsT>& istr, const bistreamable_hard2&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard2::value + 100);
      return istr;
  }
  
  
  void test_ostream_character_detection();
  void test_istream_character_detection();
  void test_mixed_stream_character_detection();
  
  boost::unit_test::test_suite *init_unit_test_suite(int, char *[])
  {
      boost::unit_test::test_suite *suite = 
          BOOST_TEST_SUITE("lexical_cast stream character detection");
      suite->add(BOOST_TEST_CASE(&test_ostream_character_detection));
      suite->add(BOOST_TEST_CASE(&test_istream_character_detection));
      suite->add(BOOST_TEST_CASE(&test_mixed_stream_character_detection));
      
      return suite;
  }
  
  template <class T>
  static void test_ostr_impl() {
      T streamable;
      BOOST_CHECK_EQUAL(T::value,  boost::lexical_cast<int>(streamable));
      BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(T::value),  boost::lexical_cast<std::string>(streamable));
  }
  
  template <class T>
  static void test_wostr_impl() {
      T streamable;
      BOOST_CHECK_EQUAL(T::value,  boost::lexical_cast<int>(streamable));
      // BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(T::value), boost::lexical_cast<std::string>(streamable)); // Shall not compile???
      BOOST_CHECK(boost::lexical_cast<std::wstring>(T::value) == boost::lexical_cast<std::wstring>(streamable));
  }
  
  template <class T>
  static void test_bistr_impl() {
      T streamable;
  
      BOOST_CHECK_EQUAL(T::value,  boost::lexical_cast<int>(streamable));
      BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(T::value),  boost::lexical_cast<std::string>(streamable));
  
      BOOST_CHECK(boost::lexical_cast<std::wstring>(T::value + 100) == boost::lexical_cast<std::wstring>(streamable));
  }
  
  void test_ostream_character_detection() {
      test_ostr_impl<streamable_easy>();
      test_ostr_impl<streamable_medium>();
      test_ostr_impl<streamable_hard>();
      test_ostr_impl<streamable_hard2>();
      
      test_wostr_impl<wstreamable_easy>();
      test_wostr_impl<wstreamable_medium>();
      test_wostr_impl<wstreamable_hard>();
      test_wostr_impl<wstreamable_hard2>();
      
      test_bistr_impl<bistreamable_easy>();
      test_bistr_impl<bistreamable_medium>();
      test_bistr_impl<bistreamable_hard>();
      test_bistr_impl<bistreamable_hard2>();
  }
  
  
  template <class T>
  static void test_istr_impl() {
      boost::lexical_cast<T>(T::value);
      boost::lexical_cast<T>(boost::lexical_cast<std::string>(T::value));
  }
  
  template <class T>
  static void test_wistr_impl() {
      boost::lexical_cast<T>(T::value);
      //boost::lexical_cast<T>(boost::lexical_cast<std::string>(T::value)); // Shall not compile???
      boost::lexical_cast<T>(boost::lexical_cast<std::wstring>(T::value));
  }
  
  template <class T>
  static void test_bistr_instr_impl() {
      boost::lexical_cast<T>(T::value);
      boost::lexical_cast<T>(boost::lexical_cast<std::string>(T::value));
      boost::lexical_cast<T>(boost::lexical_cast<std::wstring>(T::value + 100));
  }
  
  void test_istream_character_detection() {
      test_istr_impl<streamable_easy>();
      test_istr_impl<streamable_medium>();
      test_istr_impl<streamable_hard>();
      test_istr_impl<streamable_hard2>();
      
      test_wistr_impl<wstreamable_easy>();
      test_wistr_impl<wstreamable_medium>();
      test_wistr_impl<wstreamable_hard>();
      test_wistr_impl<wstreamable_hard2>();
      
      test_bistr_instr_impl<bistreamable_easy>();
      test_bistr_instr_impl<bistreamable_medium>();
      test_bistr_instr_impl<bistreamable_hard>();
      test_bistr_instr_impl<bistreamable_hard2>();
  }
  
  
  
  
  
  
  struct wistreamble_ostreamable { enum ENU {value = 200}; };
  std::ostream& operator << (std::ostream& ostr, const wistreamble_ostreamable&) {
      return ostr << wistreamble_ostreamable::value;
  }
  std::wistream& operator >> (std::wistream& istr, const wistreamble_ostreamable&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, wistreamble_ostreamable::value);
      return istr;
  }
  
  struct istreamble_wostreamable { enum ENU {value = 201}; };
  std::wostream& operator << (std::wostream& ostr, const istreamble_wostreamable&) {
      return ostr << istreamble_wostreamable::value;
  }
  std::istream& operator >> (std::istream& istr, const istreamble_wostreamable&) {
      int i; istr >> i; BOOST_CHECK_EQUAL(i, istreamble_wostreamable::value);
      return istr;
  }
  
  void test_mixed_stream_character_detection() {
      //boost::lexical_cast<std::wstring>(std::string("qwe")); // TODO: ALLOW IT AS EXTENSION!
      
      boost::lexical_cast<wistreamble_ostreamable>(wistreamble_ostreamable::value);
      BOOST_CHECK_EQUAL(boost::lexical_cast<int>(wistreamble_ostreamable()), wistreamble_ostreamable::value);
      
      boost::lexical_cast<istreamble_wostreamable>(istreamble_wostreamable::value);
      BOOST_CHECK_EQUAL(boost::lexical_cast<int>(istreamble_wostreamable()), istreamble_wostreamable::value);
  }
  