| /*************************************************************************** |
| * |
| * 27.ostream.cpp - test exercising class template basic_ostream |
| * |
| * $Id$ |
| * |
| *************************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed |
| * with this work for additional information regarding copyright |
| * ownership. The ASF licenses this file to you under the Apache |
| * License, Version 2.0 (the "License"); you may not use this file |
| * except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| * implied. See the License for the specific language governing |
| * permissions and limitations under the License. |
| * |
| * Copyright 2002-2006 Rogue Wave Software. |
| * |
| **************************************************************************/ |
| |
| |
| #include <exception> // for uncaught_exception() |
| #include <ostream> // for basic_ostream |
| #include <climits> // for XXX_MAX and XXX_MIN |
| #include <cstddef> // for ptrdiff_t |
| #include <cstring> // for memset() |
| |
| #include <any.h> // for rw_any_t() |
| #include <driver.h> // for rw_test() |
| |
| /***************************************************************************/ |
| |
| int rw_opt_sentry; // for --enable/disable-sentry |
| int rw_opt_formatted; // for --enable/disable-formatted |
| int rw_opt_unformatted; // for --enable/disable-unformatted |
| int rw_opt_flush; // for --enable/disable-flush |
| int rw_opt_exceptions; // for --enable/disable-exceptions |
| |
| /***************************************************************************/ |
| |
| enum streambuf_failure { |
| Setbuf = 1, Seekoff, Seekpos, Shwomanyc, Xsgetn, |
| Underflow, Uflow, Overflow, Pbackfail, Xsputn, Sync |
| }; |
| |
| |
| template <class charT> |
| struct test_streambuf: std::basic_streambuf<charT, std::char_traits<charT> > |
| { |
| typedef charT char_type; |
| typedef std::char_traits<charT> traits_type; |
| typedef std::basic_streambuf<char_type, traits_type> Streambuf; |
| typedef typename Streambuf::int_type int_type; |
| typedef typename Streambuf::off_type off_type; |
| typedef typename Streambuf::pos_type pos_type; |
| |
| test_streambuf (std::basic_ios<char_type, traits_type> *pstrm) |
| : Streambuf (), buf_ (0), bufsize_ (0), |
| throws_ (streambuf_failure ()), fails_ (streambuf_failure ()), |
| pstrm_ (pstrm) { |
| std::memset (ncalls_, 0, sizeof ncalls_); |
| this->setp (buf_, buf_); |
| } |
| |
| test_streambuf (charT *buf, std::streamsize bufsize) |
| : Streambuf (), buf_ (buf), bufsize_ (bufsize), |
| throws_ (streambuf_failure ()), fails_ (streambuf_failure ()) { |
| std::memset (ncalls_, 0, sizeof ncalls_); |
| this->setp (buf_, buf_); |
| } |
| |
| bool test (streambuf_failure) const; |
| |
| virtual Streambuf* setbuf (char_type*, std::streamsize) { |
| return test (Setbuf) ? this : 0; |
| } |
| |
| virtual pos_type |
| seekoff (off_type, std::ios_base::seekdir, std::ios_base::openmode) { |
| test (Seekoff); |
| return pos_type (off_type (-1)); |
| } |
| |
| virtual pos_type |
| seekpos (pos_type, std::ios_base::openmode) { |
| test (Seekpos); |
| return pos_type (off_type (-1)); |
| } |
| |
| virtual std::streamsize showmanyc () { |
| test (Shwomanyc); |
| return 0; |
| } |
| |
| virtual std::streamsize xsgetn (char_type*, std::streamsize) { |
| test (Xsgetn); |
| return 0; |
| } |
| |
| virtual int_type underflow () { |
| test (Underflow); |
| return traits_type::eof (); |
| } |
| |
| virtual int_type uflow () { |
| test (Uflow); |
| return traits_type::eof (); |
| } |
| |
| virtual int_type |
| overflow (int_type = traits_type::eof ()); |
| |
| virtual int_type |
| pbackfail (int_type = traits_type::eof ()) { |
| test (Pbackfail); |
| return traits_type::eof (); |
| } |
| |
| virtual std::streamsize |
| xsputn (const char_type *buf, std::streamsize bufsize) { |
| if (!test (Xsputn)) |
| return 0; |
| return Streambuf::xsputn (buf, bufsize); |
| } |
| |
| virtual int sync () { |
| if (!test (Sync)) |
| return -1; |
| |
| if (pstrm_) |
| pstrm_->setstate (std::ios_base::failbit); |
| |
| return 0; |
| } |
| |
| char_type *buf_; |
| std::streamsize bufsize_; |
| |
| int ncalls_ [Sync + 1]; // number of calls made to each function |
| |
| streambuf_failure throws_; // exception value to throw |
| streambuf_failure fails_; // which function to fail |
| |
| std::basic_ios<char_type, traits_type> *pstrm_; |
| |
| static int fail_when_; // call number on which to fail |
| }; |
| |
| |
| template <class charT> |
| int test_streambuf<charT>::fail_when_ = 1; |
| |
| |
| template <class charT> |
| bool |
| test_streambuf<charT>::test (streambuf_failure which) const |
| { |
| ++_RWSTD_CONST_CAST (test_streambuf*, this)->ncalls_ [which]; |
| |
| if (ncalls_ [which] == fail_when_ && throws_ == which) |
| throw which; |
| |
| return fails_ != which || ncalls_ [which] != fail_when_; |
| } |
| |
| |
| template <class charT> |
| typename test_streambuf<charT>::int_type |
| test_streambuf<charT>::overflow (int_type c /* = traits_type::eof () */) |
| { |
| if (!test (Overflow)) |
| return traits_type::eof (); |
| |
| if (traits_type::eq_int_type (c, traits_type::eof ())) |
| return traits_type::not_eof (c); |
| |
| const std::ptrdiff_t pptr_off = this->pptr () - this->pbase (); |
| |
| if ( this->pptr () == this->epptr () |
| && this->epptr () < buf_ + bufsize_) { |
| this->setp (buf_, this->epptr () + 1); |
| this->pbump (pptr_off + 1); |
| *(this->pptr () - 1) = traits_type::to_char_type (c); |
| return c; |
| } |
| |
| return traits_type::eof (); |
| } |
| |
| |
| |
| enum num_put_overload { |
| Bool = Sync + 1, Long, ULong, Dbl, LDbl, PVoid, LLong, ULLong |
| }; |
| |
| |
| #ifndef _RWSTD_NO_NATIVE_BOOL |
| |
| num_put_overload select_overload (bool) { return Bool; } |
| |
| #endif // _RWSTD_NO_NATIVE_BOOL |
| |
| template <class T> |
| num_put_overload select_overload (T) { return num_put_overload (); } |
| |
| num_put_overload select_overload (short) { return Long; } |
| num_put_overload select_overload (unsigned short) { return ULong; } |
| num_put_overload select_overload (int) { return Long; } |
| num_put_overload select_overload (unsigned int) { return ULong; } |
| num_put_overload select_overload (long) { return Long; } |
| num_put_overload select_overload (unsigned long) { return ULong; } |
| |
| #ifdef _RWSTD_LONG_LONG |
| |
| num_put_overload select_overload (_RWSTD_LONG_LONG) { return Long; } |
| num_put_overload select_overload (unsigned _RWSTD_LONG_LONG) { return ULong; } |
| |
| #endif |
| |
| num_put_overload select_overload (float) { return Dbl; } |
| num_put_overload select_overload (double) { return Dbl; } |
| |
| #ifndef _RWSTD_NO_LONG_DOUBLE |
| |
| num_put_overload select_overload (long double) { return LDbl; } |
| |
| #endif // _RWSTD_NO_LONG_DOUBLE |
| |
| num_put_overload select_overload (const void*) { return PVoid; } |
| |
| |
| template <class charT> |
| struct test_num_put: std::num_put<charT, std::ostreambuf_iterator<charT> > |
| { |
| typedef charT char_type; |
| typedef std::ostreambuf_iterator<charT> iter_type; |
| typedef std::num_put<charT, iter_type> NumPut; |
| typedef std::ios_base Ios; |
| |
| explicit test_num_put (std::size_t refs = 0) |
| : NumPut (refs), |
| throws_ (num_put_overload ()), |
| fails_ (num_put_overload ()) { |
| std::memset (ncalls_, 0, sizeof ncalls_); |
| } |
| |
| iter_type test (iter_type, num_put_overload) const; |
| |
| #define TEST(it, val) test (it, select_overload (val)) |
| |
| #ifndef _RWSTD_NO_NATIVE_BOOL |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, bool val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| #endif // _RWSTD_NO_NATIVE_BOOL |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, long val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, unsigned long val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, double val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, long double val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, const void *val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| #ifdef _RWSTD_LONG_LONG |
| |
| // extensions |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, |
| _RWSTD_LONG_LONG val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| virtual iter_type |
| do_put (iter_type it, Ios &fl, char_type fill, |
| unsigned _RWSTD_LONG_LONG val) const { |
| return NumPut::do_put (TEST (it, val), fl, fill, val); |
| } |
| |
| #endif // _RWSTD_LONG_LONG |
| |
| #undef TEST |
| |
| int ncalls_ [ULLong + 1]; |
| num_put_overload throws_; |
| num_put_overload fails_; |
| }; |
| |
| |
| template <class charT> |
| typename test_num_put<charT>::iter_type |
| test_num_put<charT>::test (iter_type it, num_put_overload which) const |
| { |
| ++_RWSTD_CONST_CAST (test_num_put*, this)->ncalls_ [which]; |
| |
| if (throws_ == which) |
| throw which; |
| |
| if (fails_ == which) { |
| |
| // construct an iter_type object in a failed state |
| test_streambuf<charT> tsb (0, 0); |
| iter_type failed (&tsb); |
| failed = char_type (); |
| |
| _RWSTD_ASSERT (failed.failed ()); |
| |
| return failed; |
| } |
| |
| return it; |
| } |
| |
| /***************************************************************************/ |
| |
| bool uncaught = false; |
| |
| |
| template <class charT> |
| struct DtorChek |
| { |
| typedef std::basic_ostream<charT, std::char_traits<charT> > Ostream; |
| typedef typename Ostream::sentry Sentry; |
| |
| Ostream *pstrm_; |
| |
| ~DtorChek () { |
| |
| #ifndef _RWSTD_UNCAUGHT_EXCEPTION |
| |
| uncaught = std::uncaught_exception (); |
| |
| #endif // _RWSTD_UNCAUGHT_EXCEPTION |
| |
| const Sentry guard (*pstrm_); |
| } |
| }; |
| |
| |
| template <class charT> |
| void test_sentry (charT) |
| { |
| static const char* const cname = rw_any_t (charT ()).type_name (); |
| |
| typedef std::basic_ostream<charT, std::char_traits<charT> > Ostream; |
| typedef typename Ostream::sentry Sentry; |
| |
| const Sentry *pguard = 0; |
| |
| { |
| rw_info (0, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry " |
| "(basic_ostream&)", cname); |
| |
| // verify that sentry ctor handles streams with rdbuf() == 0 |
| static Ostream strm (0); |
| |
| strm.setf (std::ios_base::unitbuf); |
| |
| // pguard will be deleted in sentry dtor block |
| pguard = new Sentry (strm); |
| } |
| |
| { |
| // verify 27.6.2.3, p2 and 3: |
| // |
| // explicit sentry(basic_ostream<charT,traits>& os); |
| // |
| // -2- If os.good() is nonzero, prepares for formatted or |
| // unformatted output. If os.tie() is not a null pointer, |
| // calls os.tie()->flush(). |
| // -3- If, after any preparation is completed, os.good() is |
| // true, ok_ == true otherwise, ok_ == false. |
| |
| // verify that sentry ctor calls stream.tie()->flush() once |
| // and that the object returns true when converted to bool |
| test_streambuf<charT> tsb_tied (0); |
| test_streambuf<charT> tsb_strm (0); |
| |
| Ostream tied (&tsb_tied); |
| Ostream strm (&tsb_strm); |
| |
| strm.tie (&tied); |
| |
| int nsyncs = tsb_tied.ncalls_ [Sync]; |
| |
| const Sentry guard (strm); |
| |
| rw_assert (1 + nsyncs == tsb_tied.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry " |
| "(basic_ostream &s) called s.tie ()->flush() once; " |
| "got %d times", |
| cname, tsb_tied.ncalls_ [Sync] - nsyncs); |
| |
| rw_info (0, 0, __LINE__, "std::basic_ostream<%s>::sentry::operator " |
| "bool () const", cname); |
| |
| rw_assert (bool (guard), 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::operator bool() == true " |
| "after a successful construction", cname); |
| } |
| |
| { |
| // verify 27.6.2.3, p3: i.e., same as above, but check that |
| // the ctor sets ok_ to false after the preparation fails |
| // (which is done by having stream.tie()->flush() call |
| // stream.setf (failbit)) |
| |
| test_streambuf<charT> tsb_strm (0); |
| Ostream strm (&tsb_strm); |
| |
| // create a use-defined streambuf object and associate it |
| // with the stream object, strm, constructed above so that |
| // when the latter calls strm.tie()->flush() the former |
| // can set failbit in strm |
| test_streambuf<charT> tsb_tied (&strm); |
| Ostream tied (&tsb_tied); |
| |
| // tie the two streams together |
| strm.tie (&tied); |
| |
| // sentry ctor calls strm.tie()->flush() which sets failbit |
| // in strm's; the sentry ctor should detect this condition |
| const Sentry guard (strm); |
| |
| rw_assert (!guard, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::operator bool() == " |
| "false after a failed construction (stream.rdstate() " |
| "== %{Is})", cname, strm.rdstate ()); |
| } |
| |
| { |
| // verify 27.6.2.3, p3: i.e., same as above, but check that |
| // stream.tie()->flush() is not called when stream.good() is |
| // false |
| |
| test_streambuf<charT> tsb_strm (0); |
| Ostream strm (&tsb_strm); |
| |
| // create a use-defined streambuf object and associate it |
| // with the stream object, strm, constructed above to keep |
| // track of the number of any calls to sync() from flush() |
| test_streambuf<charT> tsb_tied (&strm); |
| Ostream tied (&tsb_tied); |
| |
| // tie the two streams together |
| strm.tie (&tied); |
| |
| strm.setstate (std::ios_base::failbit); |
| |
| // sentry ctor should not call strm.tie()->flush() if |
| // strm.good() returns false |
| const Sentry guard (strm); |
| |
| rw_assert (!tsb_tied.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry(basic_ostream&) " |
| "unexpectedly called stream.tie()->flush() when " |
| "stream.good() == false", cname); |
| |
| rw_assert (!guard, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::operator bool() == " |
| "false for a stream whose stream.rdstate() = %{Is}", |
| cname, strm.rdstate ()); |
| } |
| |
| #ifndef _RWSTD_NO_EXCEPTIONS |
| |
| if (0 <= rw_opt_exceptions) { |
| |
| test_streambuf<charT> tsb_strm (0); |
| Ostream strm (&tsb_strm); |
| |
| test_streambuf<charT> tsb_tied (&strm); |
| Ostream tied (&tsb_tied); |
| |
| strm.tie (&tied); |
| |
| tsb_tied.throws_ = Sync; |
| |
| // verify that an exception thrown during the call to |
| // strm.tie()->flush() is caught and not propagated, and in |
| // response to it badbit is set in the tied stream, but that |
| // strm is not affected in any way |
| try { |
| |
| // sentry ctor calls strm.tie()->flush() which should call |
| // strm.tie()->flush() (or its equivalent), which in turn |
| // calls rdbuf()->pubsync() which throws an exception (from |
| // the virtual overridden above) |
| // the sentry ctor must not prevent badbit from being set |
| // in the tied stream but it must not allow the exception |
| // to propagate to its caller |
| const Sentry guard (strm); |
| |
| rw_assert (!!guard, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::operator bool() == " |
| "true after it failed to flush a tied stream due to " |
| "an exception (stream.rdstate() == %{Is})", |
| cname, strm.rdstate ()); |
| } |
| catch (...) { |
| rw_assert (false, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry(basic_ostream&)" |
| " unexpectedly allowed an exception to propagate", |
| cname); |
| } |
| |
| // verify that the sentry ctor did not affect the state of the stream |
| // as a result of the exception thrown during the flushing of the tied |
| // stream |
| rw_assert (strm.good (), 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry(basic_ostream&) " |
| "unexpectedly affected the state of the stream as a result " |
| "pf an exception thrown during the flushing of a tied " |
| "stream; stream state = %{Is}", cname, strm.rdstate ()); |
| |
| // verify that the the tied stream object's state has set badbit |
| // in response to the exception thrown from its stream buffer |
| rw_assert (tied.bad (), 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::sentry(basic_ostream&) " |
| "failed to cause badbit to be set in stream's tied object " |
| "after an exception; tied stream's state = %{Is}", |
| cname, tied.rdstate ()); |
| } |
| |
| #endif // _RWSTD_NO_EXCEPTIONS |
| |
| { |
| rw_info (0, 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::~sentry()", cname); |
| |
| // verify that sentry dtor handles streams with rdbuf() == 0 |
| |
| // pguard dynamically constructed in sentry ctor block |
| delete pguard; |
| } |
| |
| { |
| // verify 27.6.2.3, p4: |
| // |
| // ~sentry(); |
| // |
| // -4- If ((os.flags() & iose::unitbuf) && !uncaught_exception()) |
| // is true, calls os.flush(). |
| |
| test_streambuf<charT> tsb (0); |
| Ostream strm (&tsb); |
| |
| int nsyncs; |
| |
| // verify that os.flush() is not called if ios::unitbuf is clear |
| { |
| const Sentry guard (strm); |
| |
| nsyncs = tsb.ncalls_ [Sync]; |
| } |
| |
| rw_assert (nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::~sentry() unexpectedly " |
| "called stream.flush () when ios::unitbuf is clear", |
| cname); |
| |
| // verify that os.flush() is called if ios::unitbuf is set |
| // (assuming uncaugt_exception() returns false |
| { |
| strm.setf (std::ios_base::unitbuf); |
| |
| const Sentry guard (strm); |
| |
| nsyncs = tsb.ncalls_ [Sync]; |
| } |
| |
| rw_assert (1 + nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::~sentry() failed to call " |
| "stream.flush () when ios::unitbuf is set", |
| cname); |
| |
| #ifndef _RWSTD_NO_EXCEPTIONS |
| # ifndef _RWSTD_NO_UNCAUGHT_EXCEPTION |
| |
| if (0 <= rw_opt_exceptions) { |
| |
| // verify that os.flush() is not called if ios::unitbuf is set |
| // but uncaught_exception() returns true |
| |
| nsyncs = tsb.ncalls_ [Sync]; |
| |
| try { |
| strm.setf (std::ios_base::unitbuf); |
| |
| DtorChek<charT> to_be_destroyed; |
| |
| to_be_destroyed.pstrm_ = &strm; |
| |
| throw 0; |
| } |
| catch (...) { |
| } |
| |
| rw_assert (nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::sentry::~sentry() " |
| "unexpectedly called stream.flush() when " |
| "ios::unitbuf is set but uncaught_exception() " |
| "returns true", cname); |
| |
| rw_assert (uncaught, 0, __LINE__, |
| "std::uncaught_exception () == true when an exception " |
| "is pending (language runtime library error)"); |
| } |
| |
| # endif // _RWSTD_NO_UNCAUGHT_EXCEPTION |
| #endif // _RWSTD_NO_EXCEPTIONS |
| |
| } |
| } |
| |
| |
| /***************************************************************************/ |
| |
| |
| // for convenience |
| #define Boolalpha std::ios_base::boolalpha |
| #define Dec std::ios_base::dec |
| #define Fixed std::ios_base::fixed |
| #define Hex std::ios_base::hex |
| #define Internal std::ios_base::internal |
| #define Left std::ios_base::left |
| #define Oct std::ios_base::oct |
| #define Right std::ios_base::right |
| #define Scientific std::ios_base::scientific |
| #define Showbase std::ios_base::showbase |
| #define Showpoint std::ios_base::showpoint |
| #define Showpos std::ios_base::showpos |
| #define Skipws std::ios_base::skipws |
| #define Unitbuf std::ios_base::unitbuf |
| #define Uppercase std::ios_base::uppercase |
| #define Bin std::ios_base::bin |
| #define Adjustfield std::ios_base::adjustfield |
| #define Basefield std::ios_base::basefield |
| #define Floatfield std::ios_base::floatfield |
| #define Nolock std::ios_base::nolock |
| #define Nolockbuf std::ios_base::nolockbuf |
| |
| #define Bad std::ios_base::badbit |
| #define Eof std::ios_base::eofbit |
| #define Fail std::ios_base::failbit |
| #define Good std::ios_base::goodbit |
| |
| |
| const int Throw = 1 << 16; |
| |
| |
| template <class charT, class T> |
| void test_formatted (charT, int line1, int line2, |
| T val, |
| const char *str, |
| int fmtflags, |
| int width, |
| int fill, |
| int rdstate, |
| int exceptions, |
| int failure = 0, |
| int fail_when = 1) |
| { |
| static const char* const cname = rw_any_t (charT ()).type_name (); |
| static const char* const tname = rw_any_t (T ()).type_name (); |
| |
| typedef std::basic_ostream<charT, std::char_traits<charT> > Ostream; |
| |
| charT charbuf [256] = { 0 }; |
| |
| // define prior to the definition of `tsb' below |
| // to guarantee the proper order of destruction |
| test_num_put<charT> tnp (1); |
| |
| test_streambuf<charT> tsb (charbuf, sizeof charbuf / sizeof *charbuf); |
| |
| if (failure & Throw) { |
| failure &= ~Throw; |
| |
| if (failure < Bool) |
| tsb.throws_ = streambuf_failure (failure); |
| else |
| tnp.throws_ = num_put_overload (failure); |
| } |
| else { |
| if (failure < Bool) |
| tsb.fails_ = streambuf_failure (failure); |
| else |
| tnp.fails_ = num_put_overload (failure); |
| } |
| |
| tsb.fail_when_ = fail_when; |
| |
| Ostream os (&tsb); |
| |
| if (select_overload (T ())) { |
| |
| // for arithmetic types and void*, imbue a custom num_put facet |
| os.imbue (std::locale (std::locale::classic (), &tnp)); |
| } |
| |
| os.flags (std::ios_base::fmtflags (fmtflags)); |
| os.width (std::streamsize (width)); |
| os.exceptions (std::ios_base::iostate (exceptions)); |
| |
| if (-1 != fill) |
| os.fill (charT (fill)); |
| |
| enum { E_unknown = 1, E_failure }; |
| int caught = 0; |
| |
| const char *caught_what = "none (none thrown)"; |
| |
| try { |
| os << val; |
| } |
| catch (streambuf_failure e) { |
| caught = e; |
| caught_what = "streambuf_failure"; |
| } |
| catch (num_put_overload e) { |
| caught = e; |
| caught_what = "num_put_overload"; |
| } |
| catch (const std::ios_base::failure&) { |
| caught = E_failure; |
| caught_what = "std::ios_base::failure"; |
| } |
| catch (...) { |
| caught = E_unknown; |
| caught_what = "unknown exception"; |
| } |
| |
| if (str) { |
| char cbuf [256] = ""; |
| for (std::size_t i = 0; i != sizeof cbuf && str [i]; ++i) |
| cbuf [i] = char (charbuf [i]); |
| |
| rw_assert (0 == std::strcmp (cbuf, str), __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "inserted \"%s\", expected \"%s\"", |
| line2, cname, tname, cbuf, str); |
| } |
| |
| // verify that stream is in the expected state |
| rw_assert (rdstate == os.rdstate (), __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc})" |
| ".rdstate() == %{Is}, got %{Is}", |
| line2, cname, tname, val, rdstate, os.rdstate ()); |
| |
| if (!tsb.throws_ && !tnp.throws_) { |
| |
| bool pass; |
| |
| #ifdef _RWSTD_NO_EXT_KEEP_WIDTH_ON_FAILURE |
| // verify that width(0) has been called (unless there are exceptions |
| // involved, in which case it's unspecified whether width(0) has or |
| // has not been called |
| pass = !((!exceptions || !tsb.fails_ && !tnp.fails_) && os.width ()); |
| |
| rw_assert (pass, __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc})" |
| ".width () == 0, got %d", |
| line2, cname, tname, val, os.width ()); |
| #endif // _RWSTD_NO_EXT_KEEP_WIDTH_ON_FAILURE |
| |
| // verify that ios_base::failure has been thrown (and caught) |
| // if badbit is set in exceptions |
| pass = !(exceptions & os.rdstate () && caught != E_failure); |
| |
| rw_assert (pass, __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "set %{Is} but failed to throw ios_base::failure " |
| "when the same bit is set in exceptions", |
| line2, cname, tname, val, rdstate); |
| } |
| |
| if (tsb.throws_) { |
| |
| // verify that the same exception (and not ios_base::failure) |
| // as the one thrown from basic_filebuf has been propagated |
| // and caught when badbit is set in exceptions, and that no |
| // exception has been thrown if exceptions is clear |
| if (exceptions & Bad && caught != tsb.throws_) { |
| |
| rw_assert (false, __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "failed to propagate an exception thrown by " |
| "basic_filebuf; caught %s instead", |
| line2, cname, tname, val, caught_what); |
| } |
| else { |
| rw_assert ((exceptions & Bad) || !caught, 0, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "propagated an exception thrown by basic_filebuf " |
| "when ios_base::badbit is clear in exceptions", |
| line2, cname, tname, val); |
| } |
| } |
| |
| if (tnp.throws_) { |
| |
| // verify that the same exception (and not ios_base::failure) |
| // as the one thrown from num_put has been propagated and caught |
| // when badbit is set in exceptions, and that no exception has |
| // been thrown if exceptions is clear |
| if (exceptions & Bad) |
| rw_assert (caught == tnp.throws_, 0, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "failed to propagate exception thrown by " |
| "basic_filebuf; caught %s instead", |
| line2, cname, tname, val, caught_what); |
| else |
| rw_assert (!caught, __FILE__, line1, |
| "%d. std::basic_ostream<%s>::operator<<(%s = %{#lc}) " |
| "propagated an exception thrown by basic_filebuf" |
| "when ios_base::badbit is clear in exceptions", |
| line2, cname, tname, val); |
| } |
| } |
| |
| /***************************************************************************/ |
| |
| template <class charT> |
| bool is_char (charT) { return false; } |
| |
| bool is_char (char) { return true; } |
| bool is_char (signed char) { return true; } |
| bool is_char (unsigned char) { return true; } |
| |
| bool is_char (const char*) { return true; } |
| bool is_char (const signed char*) { return true; } |
| bool is_char (const unsigned char*) { return true; } |
| |
| template <class charT> |
| bool is_wchar_t (charT) { return false; } |
| |
| #ifndef _RWSTD_NO_WCHAR_T |
| |
| bool is_wchar_t (wchar_t) { return true; } |
| bool is_wchar_t (const wchar_t*) { return true; } |
| |
| #endif // _RWSTD_NO_WCHAR_T |
| |
| |
| template <class charT, class T> |
| void test_formatted (charT, int line, T val, |
| int flags, int width, const char *str, int fill = -1) |
| { |
| static const char* const cname = rw_any_t (charT ()).type_name (); |
| static const char* const tname = rw_any_t (T ()).type_name (); |
| |
| static int done = 0; |
| |
| if (!done++) { |
| // show message only the first time for each specialization |
| |
| if (is_char (T ()) || is_wchar_t (T ())) |
| rw_info (0, 0, __LINE__, |
| "std::operator<<(basic_ostream<%s>&, %s)", cname, tname); |
| else |
| rw_info (0, 0, __LINE__, |
| "std::basic_ostream<%s>::operator<<(%s)", cname, tname); |
| } |
| |
| // determine which overload of num_put::put() is expected |
| // to be called for a value of type T; 0 for non-numeric |
| const int npo = select_overload (val); |
| |
| typedef std::basic_ostream<charT, std::char_traits<charT> > Ostream; |
| |
| #define T charT (), line, __LINE__ |
| #define TEST test_formatted |
| |
| TEST (T, val, str, flags, width, fill, Good, 0, 0); |
| |
| if (npo) { |
| // exercise the behavior of basic_ostream with exception bits |
| // clear when num_put fails by returning an ostreambuf_iterator |
| // in a failed state (expect ios::badbit to be set w/o throwing |
| // an exception) |
| TEST (T, val, "", flags, width, fill, Bad, 0, npo); |
| |
| // exercise the behavior of basic_ostream with ios::badbit |
| // set in exceptions when num_put fails by returning an |
| // ostreambuf_iterator in a failed state (expect ios::badbit |
| // to be set and ios::failure to be thrown) |
| TEST (T, val, "", flags, width, fill, Bad, Bad, npo); |
| |
| // exercise the behavior of basic_ostream with exceptions bits |
| // clear when num_put fails by throwing an exception (expect |
| // ios::badbit to be set and no exception to propagate) |
| TEST (T, val, "", flags, width, fill, Bad, 0, Throw | npo); |
| |
| // exercise the behavior of basic_ostream with ios::badbit |
| // set in exceptions when num_put fails by throwing an exception |
| // (expect ios::badbit to be set and the original exception to |
| // propagate) |
| TEST (T, val, "", flags, width, fill, Bad, Bad, Throw | npo); |
| } |
| |
| // exercise the behavior of basic_ostream with exception bits clear |
| // when basic_streambuf::overflow() fails by returning eof() (expect |
| // ios::badbit to be set w/o throwing an exception) |
| TEST (T, val, "", flags, width, fill, Bad, 0, Overflow); |
| |
| // exercise the behavior of basic_ostream with ios::badbit set in |
| // exceptions when basic_streambuf::overlow() fails by returning |
| // eof() (expect ios::badbit to be set and ios::failure to be thrown) |
| TEST (T, val, "", flags, width, fill, Bad, Bad, Overflow); |
| |
| // exercise the behavior of basic_ostream with exceptions bits clear |
| // when basic_streambuf::overlow() fails by throwing an exception |
| // (expect ios::badbit to be set and no exception to propagate) |
| TEST (T, val, "", flags, width, fill, Bad, 0, Throw | Overflow); |
| |
| // exercise the behavior of basic_ostream with ios::badbit set in |
| // exceptions when basic_streambuf::overflow() fails by throwing |
| // an exception (expect ios::badbit to be set and the original |
| // exception to propagate) |
| TEST (T, val, "", flags, width, fill, Bad, Bad, Throw | Overflow); |
| } |
| |
| /***************************************************************************/ |
| |
| |
| template <class charT> |
| void test_formatted (charT) |
| { |
| #undef T |
| #define T(val) charT (), __LINE__, val |
| |
| #undef TEST |
| #define TEST test_formatted |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise operator<< (basic_ostream, char) |
| |
| // +------------ character to insert |
| // | +------- fmtflags |
| // | | +---- field width |
| // | | | +- expected output |
| // | | | | |
| // v v v v |
| TEST (T ('a'), 0, 0, "a"); |
| TEST (T ('A'), 0, 0, "A"); |
| TEST (T ('@'), 0, 1, "@"); |
| TEST (T ('#'), 0, 2, " #"); |
| |
| if (is_wchar_t (charT ())) { |
| |
| #ifndef _RWSTD_NO_NATIVE_WCHAR_T |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise operator<< (basic_ostream, wchar_t) |
| TEST (T (L'b'), 0, 0, "b"); |
| TEST (T (L'B'), 0, 0, "B"); |
| |
| #endif // _RWSTD_NO_NATIVE_WCHAR_T |
| |
| } |
| else { |
| |
| // no operator<< (basic_ostream<wchar_t>, {signed,unsigned} char) |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise operator<< (basic_ostream, signed char) |
| typedef signed char SChar; |
| |
| TEST (T (SChar ('b')), 0, 0, "b"); |
| TEST (T (SChar ('B')), 0, 0, "B"); |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise operator<< (basic_ostream, signed char) |
| typedef unsigned char UChar; |
| |
| TEST (T (UChar ('c')), 0, 0, "c"); |
| TEST (T (UChar ('C')), 0, 0, "C"); |
| } |
| |
| |
| #ifndef _RWSTD_NO_NATIVE_BOOL |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (bool) |
| TEST (T (false), 0, 0, "0"); |
| TEST (T (true), 0, 0, "1"); |
| |
| TEST (T (false), Hex | Showbase, 0, "0"); |
| TEST (T (true), Hex | Showbase, 0, "0x1"); |
| |
| TEST (T (false), Boolalpha, 0, "false"); |
| TEST (T (true), Boolalpha, 0, "true"); |
| |
| #endif // _RWSTD_NO_NATIVE_BOOL |
| |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (short) |
| TEST (T (short ( 0)), 0, 0, "0"); |
| TEST (T (short ( 1)), 0, 0, "1"); |
| TEST (T (short (-1)), 0, 0, "-1"); |
| |
| #if SHRT_MAX == 32767 |
| |
| TEST (T (short (SHRT_MAX)), 0, 0, "32767"); |
| TEST (T (short (SHRT_MIN)), 0, 0, "-32768"); |
| |
| TEST (T (short (SHRT_MAX)), Hex, 0, "7fff"); |
| TEST (T (short (SHRT_MIN)), Hex, 0, "8000"); |
| |
| #elif SHRT_MAX == 2147483647 |
| |
| TEST (T (short (SHRT_MAX)), 0, 0, "2147483647"); |
| TEST (T (short (SHRT_MIN)), 0, 0, "-2147483648"); |
| |
| TEST (T (short (SHRT_MAX)), Hex, 0, "ffffffff"); |
| TEST (T (short (SHRT_MIN)), Hex, 0, "80000000"); |
| |
| #endif // SHRT_MAX |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (unsigned short) |
| typedef unsigned short UShort; |
| |
| TEST (T (UShort ( 0)), 0, 0, "0"); |
| TEST (T (UShort ( 1)), 0, 0, "1"); |
| TEST (T (UShort (255)), 0, 0, "255"); |
| |
| #if USHRT_MAX == 0xffffU |
| |
| TEST (T (UShort (USHRT_MAX)), 0, 0, "65535"); |
| TEST (T (UShort (USHRT_MAX)), Hex, 0, "ffff"); |
| |
| #elif USHRT_MAX == 0xffffffffU |
| |
| TEST (T (UShort (SHRT_MAX)), 0, 0, "4294967295"); |
| TEST (T (UShort (SHRT_MAX)), Hex, 0, "ffffffff"); |
| |
| #endif // USHRT_MAX |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (int) |
| TEST (T ( 0), 0, 0, "0"); |
| TEST (T ( 1), 0, 0, "1"); |
| TEST (T (-1), 0, 0, "-1"); |
| |
| #if INT_MAX == 32767 |
| |
| TEST (T (INT_MAX), 0, 0, "32767"); |
| TEST (T (INT_MIN), 0, 0, "-32768"); |
| |
| TEST (T (INT_MAX), Hex, 0, "7fff"); |
| TEST (T (INT_MIN), Hex, 0, "8000"); |
| |
| #elif INT_MAX == 2147483647 |
| |
| TEST (T (INT_MAX), 0, 0, "2147483647"); |
| TEST (T (INT_MIN), 0, 0, "-2147483648"); |
| |
| TEST (T (INT_MAX), Hex, 0, "7fffffff"); |
| TEST (T (INT_MIN), Hex, 0, "80000000"); |
| |
| #elif INT_MAX == 9223372036854775807 |
| |
| TEST (T (INT_MAX), 0, 0, "9223372036854775807"); |
| TEST (T (INT_MIN), 0, 0, "-9223372036854775808"); |
| |
| TEST (T (INT_MAX), Hex, 0, "7fffffffffff"); |
| TEST (T (INT_MIN), Hex, 0, "800000000000"); |
| |
| #endif // INT_MAX |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (unsigned int) |
| TEST (T ( 0), 0, 0, "0"); |
| TEST (T ( 1), 0, 0, "1"); |
| TEST (T (255), 0, 0, "255"); |
| |
| #if UINT_MAX == 0xffffU |
| |
| TEST (T (UINT_MAX), 0, 0, "65535"); |
| TEST (T (UINT_MAX), Hex, 0, "ffff"); |
| |
| #elif UINT_MAX == 0xffffffffU |
| |
| TEST (T (UINT_MAX), 0, 0, "4294967295"); |
| TEST (T (UINT_MAX), Hex, 0, "ffffffff"); |
| |
| #elif UINT_MAX == 0xffffffffffffffffU |
| |
| TEST (T (UINT_MAX), 0, 0, "18446744073709551615"); |
| TEST (T (UINT_MAX), Hex, 0, "ffffffffffffffff"); |
| |
| #endif // UINT_MAX |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (long) |
| TEST (T ( 0L), 0, 0, "0"); |
| TEST (T ( 1L), 0, 0, "1"); |
| TEST (T (-1L), 0, 0, "-1"); |
| |
| #if LONG_MAX == 32767L |
| |
| TEST (T (LONG_MAX), 0, 0, "32767"); |
| TEST (T (LONG_MIN), 0, 0, "-32768"); |
| |
| TEST (T (LONG_MAX), Hex, 0, "7fff"); |
| TEST (T (LONG_MIN), Hex, 0, "8000"); |
| |
| #elif LONG_MAX == 2147483647L |
| |
| TEST (T (LONG_MAX), 0, 0, "2147483647"); |
| TEST (T (LONG_MIN), 0, 0, "-2147483648"); |
| |
| TEST (T (LONG_MAX), Hex, 0, "7fffffff"); |
| TEST (T (LONG_MIN), Hex, 0, "80000000"); |
| |
| #elif LONG_MAX == 9223372036854775807L |
| |
| TEST (T (LONG_MAX), 0, 0, "9223372036854775807"); |
| TEST (T (LONG_MIN), 0, 0, "-9223372036854775808"); |
| |
| TEST (T (LONG_MAX), Hex, 0, "7fffffffffff"); |
| TEST (T (LONG_MIN), Hex, 0, "800000000000"); |
| |
| #endif // LONG_MAX |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (unsigned int) |
| |
| TEST (T ( 0UL), 0, 0, "0"); |
| TEST (T ( 1UL), 0, 0, "1"); |
| TEST (T (257UL), 0, 0, "257"); |
| |
| #if ULONG_MAX == 0xffffUL |
| |
| TEST (T (ULONG_MAX), 0, 0, "65535"); |
| TEST (T (ULONG_MAX), Hex, 0, "ffff"); |
| |
| #elif ULONG_MAX == 0xffffffffUL |
| |
| TEST (T (ULONG_MAX), 0, 0, "4294967295"); |
| TEST (T (ULONG_MAX), Hex, 0, "ffffffff"); |
| |
| #elif ULONG_MAX == 0xffffffffffffffffUL |
| |
| TEST (T (ULONG_MAX), 0, 0, "18446744073709551615"); |
| TEST (T (ULONG_MAX), Hex, 0, "ffffffffffffffff"); |
| |
| #endif // ULONG_MAX |
| |
| #ifdef _RWSTD_LONG_LONG |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (long long) |
| typedef _RWSTD_LONG_LONG LongLong; |
| |
| TEST (T (LongLong ( 0)), 0, 0, "0"); |
| TEST (T (LongLong ( 1)), 0, 0, "1"); |
| TEST (T (LongLong (-1)), 0, 0, "-1"); |
| |
| // avoid using the preprocessor here to prevent warnings |
| // or errors about invalid preprocessor constants (e.g., |
| // PR #28595) |
| if (_RWSTD_LLONG_MAX == 32767L) { |
| |
| TEST (T (_RWSTD_LLONG_MAX), 0, 0, "32767"); |
| TEST (T (_RWSTD_LLONG_MIN), 0, 0, "-32768"); |
| |
| TEST (T (_RWSTD_LLONG_MAX), Hex, 0, "7fff"); |
| TEST (T (_RWSTD_LLONG_MIN), Hex, 0, "8000"); |
| } |
| else if (_RWSTD_LLONG_MAX == 2147483647L) { |
| |
| TEST (T (_RWSTD_LLONG_MAX), 0, 0, "2147483647"); |
| TEST (T (_RWSTD_LLONG_MIN), 0, 0, "-2147483648"); |
| |
| TEST (T (_RWSTD_LLONG_MAX), Hex, 0, "7fffffff"); |
| TEST (T (_RWSTD_LLONG_MIN), Hex, 0, "80000000"); |
| |
| } |
| else if (_RWSTD_LLONG_MAX > 2147483647L) { |
| |
| TEST (T (_RWSTD_LLONG_MAX), 0, 0, "9223372036854775807"); |
| TEST (T (_RWSTD_LLONG_MIN), 0, 0, "-9223372036854775808"); |
| |
| TEST (T (_RWSTD_LLONG_MAX), Hex, 0, "7fffffffffff"); |
| TEST (T (_RWSTD_LLONG_MIN), Hex, 0, "800000000000"); |
| |
| } |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (unsigned long long) |
| |
| typedef unsigned _RWSTD_LONG_LONG ULongLong; |
| |
| TEST (T (ULongLong ( 0)), 0, 0, "0"); |
| TEST (T (ULongLong ( 1)), 0, 0, "1"); |
| TEST (T (ULongLong (257)), 0, 0, "257"); |
| |
| if (_RWSTD_ULLONG_MAX == 0xffffUL) { |
| TEST (T (_RWSTD_ULLONG_MAX), 0, 0, "65535"); |
| TEST (T (_RWSTD_ULLONG_MAX), Hex, 0, "ffff"); |
| } |
| else if (_RWSTD_ULLONG_MAX == 0xffffffffUL) { |
| TEST (T (_RWSTD_ULLONG_MAX), 0, 0, "4294967295"); |
| TEST (T (_RWSTD_ULLONG_MAX), Hex, 0, "ffffffff"); |
| } |
| else if (_RWSTD_ULLONG_MAX > 0xffffffffUL) { |
| TEST (T (_RWSTD_ULLONG_MAX), 0, 0, "18446744073709551615"); |
| TEST (T (_RWSTD_ULLONG_MAX), Hex, 0, "ffffffffffffffff"); |
| } |
| |
| #endif // _RWSTD_LONG_LONG |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (float) |
| TEST (T ( 0.0f), 0, 0, "0"); |
| TEST (T ( 1.0f), 0, 0, "1"); |
| TEST (T (-2.1f), 0, 0, "-2.1"); |
| |
| // exercise the default precision of 6, which gives the maximum number |
| // of significant digits for the "%g" or "%G" conversion, which is |
| // the default for the default flags |
| TEST (T (3.1415926f), 0, 0, "3.14159"); |
| TEST (T (3.1415926f), Scientific, 0, "3.14159"); |
| |
| // exercise the default precision of 6, which gives the number of |
| // digits after the decimal point for the "%f" or "%F" conversion, |
| // which is used for the fixed flag |
| TEST (T (12.3456789f), Fixed, 0, "12.345679"); |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (double) |
| TEST (T ( 0.0), 0, 0, "0"); |
| TEST (T ( 2.0), 0, 0, "2"); |
| TEST (T (-4.2), 0, 0, "-4.2"); |
| |
| // exercise the default precision of 6, which gives the maximum number |
| // of significant digits for the "%g" or "%G" conversion, which is |
| // the default for the default flags |
| TEST (T (1.23456789), 0, 0, "1.23457"); |
| TEST (T (9.87654321), Scientific, 0, "9.87654"); |
| |
| // exercise the default precision of 6, which gives the number of |
| // digits after the decimal point for the "%f" or "%F" conversion, |
| // which is used for the fixed flag |
| TEST (T (12.3456789), Fixed, 0, "12.345679"); |
| |
| #ifndef _RWSTD_NO_LONG_DOUBLE |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (long double) |
| TEST (T ( 0.0L), 0, 0, "0"); |
| TEST (T ( 3.0L), 0, 0, "3"); |
| TEST (T (-5.3L), 0, 0, "-5.3"); |
| |
| // exercise the default precision of 6, which gives the maximum number |
| // of significant digits for the "%g" or "%G" conversion, which is |
| // the default for the default flags |
| TEST (T (1.23456789L), 0, 0, "1.23457"); |
| TEST (T (9.87654321L), Scientific, 0, "9.87654"); |
| |
| // exercise the default precision of 6, which gives the number of |
| // digits after the decimal point for the "%f" or "%F" conversion, |
| // which is used for the fixed flag |
| TEST (T (12.3456789L), Fixed, 0, "12.345679"); |
| |
| #endif // _RWSTD_NO_LONG_DOUBLE |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (const void*) |
| TEST (T ((void*)0), 0, 0, 0 /* format implementation-defined */); |
| TEST (T ((void*)1), 0, 0, 0); |
| TEST (T ((void*)0x2345), 0, 0, 0); |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (const char*) |
| TEST (T ("a"), 0, 0, "a"); |
| TEST (T ("b"), 0, -1, "b"); |
| TEST (T ("ab"), 0, 0, "ab"); |
| TEST (T ("abc"), 0, 4, " abc"); |
| TEST (T ("def"), Left, 5, "def<<", '<'); |
| TEST (T ("ghi"), Right, 6, ">>>ghi", '>'); |
| TEST (T ("jklm"), Internal, 7, " jklm"); |
| TEST (T ("nopqr"), Left | Right, 8, " nopqr"); |
| TEST (T ("stuv"), Left | Internal, 9, " stuv"); |
| TEST (T ("wxy"), Right | Internal, 10, " wxy"); |
| TEST (T ("z"), Left | Right | Internal, 11, "__________z", '_'); |
| |
| if (is_char (charT ())) { |
| |
| // inserters overloaded on signed and unsigned char* |
| // defined only for basic_ostream<char>, not wchar_t |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (const signed char*) |
| |
| #undef SCH |
| #define SCH(val) charT (), __LINE__, (const signed char*)val |
| |
| TEST (SCH ("A"), 0, 0, "A"); |
| TEST (SCH ("B"), 0, -1, "B"); |
| TEST (SCH ("AB"), 0, 0, "AB"); |
| TEST (SCH ("ABC"), 0, 4, " ABC"); |
| TEST (SCH ("DEF"), Left, 5, "DEF++", '+'); |
| TEST (SCH ("GHI"), Right, 6, "---GHI", '-'); |
| TEST (SCH ("JKLM"), Internal, 7, " JKLM"); |
| TEST (SCH ("NOPQR"), Left | Right, 8, " NOPQR"); |
| TEST (SCH ("STUV"), Left | Internal, 9, " STUV"); |
| TEST (SCH ("WXY"), Right | Internal, 10, " WXY"); |
| TEST (SCH ("Z"), Left | Right | Internal, 11, "##########Z", '#'); |
| |
| ////////////////////////////////////////////////////////////////// |
| // exercise basic_ostream::operator<< (const unsigned char*) |
| |
| #undef UCH |
| #define UCH(val) charT (), __LINE__, (const unsigned char*)val |
| |
| TEST (UCH ("Z"), 0, 0, "Z"); |
| TEST (UCH ("Y"), 0, -1, "Y"); |
| TEST (UCH ("YZ"), 0, 0, "YZ"); |
| TEST (UCH ("XYZ"), 0, 4, " XYZ"); |
| TEST (UCH ("UVW"), Left, 5, "UVW\\\\", '\\'); |
| TEST (UCH ("RST"), Right, 6, "///RST", '/'); |
| TEST (UCH ("OPQR"), Internal, 7, " OPQR"); |
| TEST (UCH ("JKLMN"), Left | Right, 8, " JKLMN"); |
| TEST (UCH ("FGHI"), Left | Internal, 9, " FGHI"); |
| TEST (UCH ("CDE"), Right | Internal, 10, " CDE"); |
| TEST (UCH ("AB"), Left | Right | Internal, 11, "^^^^^^^^^AB", '^'); |
| |
| } |
| } |
| |
| /***************************************************************************/ |
| |
| template <class charT> |
| void test_flush (charT) |
| { |
| static const char* const cname = rw_any_t (charT ()).type_name (); |
| |
| rw_info (0, 0, __LINE__, |
| "std::basic_ostream<%s>::flush() ", cname); |
| |
| typedef std::basic_ostream<charT, std::char_traits<charT> > Ostream; |
| typedef std::basic_streambuf<charT, std::char_traits<charT> > Streambuf; |
| |
| { |
| test_streambuf<charT> tsb (0); |
| Ostream strm (&tsb); |
| |
| const int nsyncs = tsb.ncalls_ [Sync]; |
| |
| strm.flush (); |
| |
| rw_assert (1 + nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::flush() called rdbuf()->sync() " |
| "once; got %d times", |
| cname, tsb.ncalls_ [Sync] - nsyncs); |
| } |
| |
| { |
| test_streambuf<charT> tsb (0); |
| Ostream strm (&tsb); |
| |
| tsb.fails_ = Sync; |
| tsb.fail_when_ = 1; |
| |
| const int nsyncs = tsb.ncalls_ [Sync]; |
| |
| strm.flush (); |
| |
| rw_assert (1 + nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::flush() called rdbuf()->sync() " |
| "once; got %zu times", |
| cname, tsb.ncalls_ [Sync] - nsyncs); |
| |
| rw_assert (std::ios_base::badbit == strm.rdstate (), 0, __LINE__, |
| "std::basic_ostream<%s>::flush() failed to set badbit " |
| "after rdbuf()->pubsync() failed; state = %{Is}", |
| cname, strm.rdstate ()); |
| } |
| |
| { |
| // exercise LWG issue 581: flush() not unformatted function |
| |
| test_streambuf<charT> tsb (0); |
| Ostream strm (&tsb); |
| |
| strm.setstate (std::ios_base::failbit); |
| |
| const int nsyncs = tsb.ncalls_ [Sync]; |
| |
| strm.flush (); |
| |
| rw_assert (nsyncs == tsb.ncalls_ [Sync], 0, __LINE__, |
| "std::basic_ostream<%s>::flush() unexpectedly made " |
| "%zu calls to rdbuf()->sync() when rdstate () == " |
| "failbit", |
| cname, tsb.ncalls_ [Sync] - nsyncs); |
| |
| rw_assert (std::ios_base::failbit == strm.rdstate (), 0, __LINE__, |
| "std::basic_ostream<%s>::flush() unexpectedly changed " |
| "state from std::ios_base::failbit to %{Is}", |
| cname, strm.rdstate ()); |
| } |
| } |
| |
| /***************************************************************************/ |
| |
| template <class charT> |
| void run_test (charT) |
| { |
| // exercise ostream::sentry |
| if (rw_opt_sentry < 0) |
| rw_note (0, 0, __LINE__, "sentry tests disabled"); |
| else |
| test_sentry (charT ()); |
| |
| // exercise formatted output functions |
| if (rw_opt_formatted < 0) |
| rw_note (0, 0, __LINE__, "tests of formatted functions disabled"); |
| else |
| test_formatted (charT ()); |
| |
| // exercise formatted output functions |
| if (rw_opt_unformatted < 0) |
| rw_note (0, 0, __LINE__, "tests of unformatted functions disabled"); |
| else { |
| // FIXME: implement this |
| // test_unformatted (charT ()); |
| } |
| |
| // exercise flush() |
| if (rw_opt_flush < 0) |
| rw_note (0, 0, __LINE__, "flush tests disabled"); |
| else |
| test_flush (charT ()); |
| } |
| |
| /***************************************************************************/ |
| |
| static int |
| run_test (int, char**) |
| { |
| run_test (char ()); |
| |
| #ifndef _RWSTD_NO_WCHAR_T |
| |
| run_test (wchar_t ()); |
| |
| #endif // _RWSTD_NO_WCHAR_T |
| |
| return 0; |
| } |
| |
| /***************************************************************************/ |
| |
| int main (int argc, char *argv[]) |
| { |
| return rw_test (argc, argv, __FILE__, |
| "lib.ostream", |
| 0 /* no comment */, |
| run_test, |
| "|-sentry~ " |
| "|-formatted~ " |
| "|-unformatted~ " |
| "|-flush~ " |
| "|-no-exceptions~ ", |
| &rw_opt_sentry, |
| &rw_opt_formatted, |
| &rw_opt_unformatted, |
| &rw_opt_flush, |
| &rw_opt_exceptions); |
| } |