void test_ctor (const charT*, const Traits*, const char *cname, const char *tname) { typedef std::basic_istream<charT, Traits> Istream; typedef typename Istream::sentry Sentry; memfun_info (__LINE__, cname, tname, "sentry (%{$ISTREAM}&, bool)"); const charT cbuf[] = { 'a', 'b', 'c', 'd', 'e', ' ', 'f', '\0' }; const std::ios_base::iostate states[] = { std::ios_base::badbit, std::ios_base::eofbit, std::ios_base::failbit, std::ios_base::goodbit, std::ios_base::badbit | std::ios_base::eofbit, std::ios_base::badbit | std::ios_base::failbit, std::ios_base::eofbit | std::ios_base::failbit, std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit }; ////////////////////////////////////////////////////////////// // exercise 27.6.1.1.2, p1: // - is.good() is true // - is.tie() is not null // = the function calls is.tie().flush() unsigned iter = 0; // iteration counter for (unsigned i = 0; i != sizeof states / sizeof *states; ++i) { for (unsigned j = 0; j != 2; ++j /* noskipws */) { Streambuf<charT, Traits> sb (cbuf, cbuf + sizeof cbuf / sizeof *cbuf); Istream is (&sb); // flush() is called iff // all of the following conditions hold const bool flush_called = is.good () && 0 != is.tie (); const Sentry guard (is, 0 != j); _RWSTD_UNUSED (guard); rw_assert (flush_called == sb.nsyncs_, 0, __LINE__, "%u. basic_istream<%s, %s>::sentry::sentry" "(basic_istream &is, bool noskipws = %d); " "expected to call is.flush () %d times, got %d" "initial is.state () = %{Is}, is.flags() & " "ios::skipws = %d", iter, cname, tname, 0 != j, flush_called, sb.nsyncs_, states [i], is.flags () & std::ios_base::skipws); ++iter; } } ////////////////////////////////////////////////////////////// // exercise 27.6.1.1.2, p1: // - is.good() is true // - noskipws is zero // - is.flags() & ios_base::skipws // = the function extracts and discards each character as long // as the next available input character c is a whitespace // character. for (unsigned i = 0; i != sizeof states / sizeof *states; ++i) { for (unsigned j = 0; j != 2; ++j /* noskipws */) { for (unsigned k = 0; k != 2; ++k /* ios_base::skipws */) { for (charT wc = charT ('a'); wc != charT ('c'); ++wc) { const Ctype<charT> ctp (1, wc); Streambuf<charT, Traits> sb (cbuf, cbuf + sizeof cbuf / sizeof *cbuf); Istream is (&sb); is.setstate (states [i]); if (k) is.setf (std::ios_base::skipws); else is.unsetf (std::ios_base::skipws); const std::locale loc = is.imbue (std::locale (is.getloc (), &ctp)); // imbue the previous locale into the stream // buffer to verify that the sentry ctor uses // the locale imbued in the stream object and // not the one in the stream buffer sb.pubimbue (loc); // a whitespace character is extracted iff // all of the following conditions hold const bool extract = is.good () && 0 == j && is.flags () & std::ios_base::skipws && cbuf [0] == wc; const Sentry guard (is, 0 != j); _RWSTD_UNUSED (guard); rw_assert (cbuf + extract == sb.pubgptr (), 0, __LINE__, "%u. %{$SENTRY}::sentry" "(%{$ISTREAM} &is, bool noskipws " "= %b); expected to extract %d " "whitespace chars ('%c') from %{*Ac}, " "extracted %u; initial is.state () = " "%{Is}, is.flags() & ios::skipws = %d", iter, j, extract + 0, char (wc), int (sizeof (*cbuf)), cbuf, sb.pubgptr () - sb.pubeback (), states [i], k); // verify that the ctor doesn't affect gcount() rw_assert (0 == is.gcount (), 0, __LINE__, "%u. %{$SENTRY}::sentry" "(%{$ISTREAM} &is = %{*Ac}, bool noskipws " "= %b); changed is.gcount() from 0 to %i", iter, int (sizeof (*cbuf)), cbuf, j, is.gcount ()); ++iter; } } } } }
void test_extractor (CharT*, Traits*, ArithmeticType*, const char *cname, const char *tname, const char *aname, int line, // printf formatting directive for ArithmeticType const char *valfmt, // character buffer (input sequence) const char *cbuf, // number of characters in buffer: std::size_t cbuf_size, // ctype and numpunct data const LocaleData &locale_data, // stream flags(): int flags, // initial stream rdstate(): int init_state, // unmasked exceptions: int exceptions, // expected exception: int expect_exception, // expected stream state after extraction: int expect_state, // expected number of extracted characters: int expect_extract, // have streambuf fail (or throw) after so many calls // to underflow() (each call extracts a single chracter): int fail_when, // initial value of the argument to extractor: ArithmeticType init_value, // expected value of the argument after extraction: ArithmeticType expect_value) { _RWSTD_UNUSED (cname); _RWSTD_UNUSED (tname); typedef std::basic_istream<CharT, Traits> Istream; typedef MyStreambuf<CharT, Traits> Streambuf; const char *fail_desc = 0; int fail_how = 0; if (fail_when < 0) { // have the stream buffer object's underflow() fail (by throwing // an exception if possible) after `fail_when' characters have // been extracted (this object calls underflow() for every char) fail_how = Underflow | Throw; fail_when = -fail_when; fail_desc = "threw"; } else if (0 < fail_when) { // have the stream buffer object's underflow() fail by returning // eof after `fail_when' characters have been extracted (this // object calls underflow() for every char) fail_how = Underflow; fail_desc = "returned EOF"; } // construct a stream buffer object and initialize its read sequence // with the character buffer Streambuf sb (cbuf, cbuf_size, fail_how, fail_when); // construct an istream object and initialize it with the user // defined streambuf object Istream is (&sb); if (-1 == flags) { // get the initial stream object's format control flags flags = is.flags (); } else { // set the stream object's format control flags is.flags (std::ios::fmtflags (flags)); } if (-1 == exceptions) { // get the initial stream object's exceptions exceptions = is.exceptions (); } else { // unmask the stream objects exceptions (must be done // before calling setstate() to prevent the latter from // throwing ios::failure) is.exceptions (std::ios::iostate (exceptions)); } if (-1 == init_state) { // get the initial stream object's state init_state = is.rdstate (); } else { // set the stream object's initial state #ifndef _RWSTD_NO_EXCEPTIONS try { is.setstate (std::ios::iostate (init_state)); } catch (...) { // ignore exceptions } #else // if defined ( _RWSTD_NO_EXCEPTIONS) is.setstate (std::ios::iostate (init_state)); #endif // _RWSTD_NO_EXCEPTIONS } // construct a locale object that treats only the specified `white' // characters as whitespace (all others are treated normally) const std::locale loc = is.imbue (make_locale ((CharT*)0, (Traits*)0, locale_data)); // imbue the previous locale into the stream buffer to verify that // the ws manipulator uses the locale imbued in the stream object // and not the one in the stream buffer sb.pubimbue (loc); // initialize the variable to the initial value to detect // the extractor setting it when it's not supposed to ArithmeticType value = init_value; // format the FUNCALL environment variable w/o writing out any output rw_fprintf (0, "%{$FUNCALL!:@}", "%{$CLASS}(%{*Ac}).operator>>(%s& = %{@}): " "initial flags() = %{If}, rdstate() = %{Is}, " "exceptions() = %{Is}, whitespace = %{#s}, numpunct = { " ".dp=%{#c}, .ts=%{#c}, .grp=%{#s}, .fn=%{#s}, .tn=%{#s} }", int (sizeof *cbuf), cbuf, aname, valfmt, init_value, flags, init_state, exceptions, locale_data.whitespace, locale_data.decimal_point, locale_data.thousands_sep, locale_data.grouping, locale_data.falsename, locale_data.truename); #ifndef _RWSTD_NO_EXCEPTIONS int caught = 0; try { is >> value; } catch (Exception&) { caught = 1; } catch (std::ios_base::failure &ex) { caught = 2; rw_assert (caught == expect_exception, 0, line, "line %d. %{$FUNCALL}: unexpectedly threw " "ios_base::failure(%{#s})", __LINE__, ex.what ()); } catch (...) { caught = -1; rw_assert (false, 0, line, "line %d. %{$FUNCALL}: unexpectely threw an exception " "of unknown type", __LINE__); } ////////////////////////////////////////////////////////////////// // verify that the function propagates exceptions thrown from the // streambuf object only when badbit is set in the stream object's // exceptions() rw_assert (caught == expect_exception, 0, line, "line %d. %{$FUNCALL}: " "%{?}failed to throw" "%{:}unexpectedly propagated" "%{;} exception", __LINE__, expect_exception); #else // if defined (_RWSTD_NO_EXCEPTIONS) is >> value; #endif // _RWSTD_NO_EXCEPTIONS // clear the text describing the type of failure when streambuf // didn't actually fail (or throw) if (sb.failed_ == None && sb.threw_ == None) fail_desc = 0; ////////////////////////////////////////////////////////////////// // verify that the expected number of characters have been // extracted from the stream const int extracted = int (sb.pubgptr () - sb.pubeback ()); rw_assert (expect_extract == extracted, 0, line, "%d. %{$FUNCALL}: expected to extract %d characters, " "got %d%{?} (underflow() %s at extraction %u)%{;}", __LINE__, expect_extract, extracted, 0 != fail_desc, fail_desc, fail_when); ////////////////////////////////////////////////////////////////// // verify that gcount() is not affected if (0 == opt_no_gcount) rw_assert (0 == is.gcount (), 0, line, "%d. %{$FUNCALL}: gcount() == 0, got %d " "%{?} (underflow() %s at extraction %u)%{;}", __LINE__, is.gcount (), 0 != fail_desc, fail_desc, fail_when); ////////////////////////////////////////////////////////////////// // verify the state of the stream object after the function call rw_assert (is.rdstate () == expect_state, 0, line, "line %d. %{$FUNCALL}: rdstate() == %{Is}, got %{Is}" "%{?} (underflow() %s at extraction %u)%{;}", __LINE__, expect_state, is.rdstate(), 0 != fail_desc, fail_desc, fail_when); ////////////////////////////////////////////////////////////////// // verify the extracted value matches the expected value rw_assert (expect_value == value, 0, line, "line %d. %{$FUNCALL}: expected value %{@}, got %{@}", __LINE__, valfmt, expect_value, valfmt, value); }