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); }
void test_readsome (const charT *cbuf, const Traits*, unsigned cbuf_size, unsigned i, // index into states unsigned j, // number of chars to read unsigned k, // when underflow() will fail int l, // value returned from showmanyc() unsigned m) // how underflow should fail() { typedef std::basic_istream<charT, Traits> Istream; static unsigned iter = 0; // iteration counter // construct a stream buffer object and initialize its read // sequence with the character buffer Streambuf<charT, Traits> sb (cbuf, cbuf + cbuf_size - 1); sb.showmanyc_ = l; const char* err_type = 0; if (m < 1) { // have the stream buffer object's underflow() fail (by // throwing an exception if possible) after k characters // have been extracted (this object calls underflow() for // every char) sb.throw_after_ = k; err_type = "threw"; } else { // have the stream buffer object's underflow() fail by // returning eof after k characters have been extracted // (this object calls underflow() for every char) sb.fail_after_ = k; err_type = "returned EOF"; } // construct an istream object and initialize it with the user // defined streambuf object Istream is (&sb); // set the stream object's initial state is.setstate (states [i]); // the number of extracted whitespace characters expected to // be reported by gcount() must equal the number of successful // extractions computed by the the stream buffer overridden // underflow member function const int extract = is.good () ? j < k ? int (j) < l ? j : l < 0 ? 0 : l : int (k) < l ? k : l < 0 ? 0 : l : 0; charT buf [256] = { 0 }; std::streamsize nread = -1; // format the FCALL environment variable so that it can be // conveniently used in diagnostics below rw_fprintf (0, "%u. %{$FCALL!:@}", iter, "%{$ISTREAM}(%{*Ac}).readsome(%p, %d)", int (sizeof *cbuf), cbuf, buf, j); #ifndef _RWSTD_NO_EXCEPTIONS const char *caught = 0; // on every other iteration set badbit in exceptions to check // that the thrown object is propagated by the function if (k % 2 && !is.bad ()) is.exceptions (std::ios_base::badbit); try { nread = is.readsome (buf, j); } catch (const char *s) { caught = s; } catch (...) { caught = "..."; rw_assert (0, 0, __LINE__, "%{$FCALL} threw an exception of unexpected type"); } ////////////////////////////////////////////////////////////////// // 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 || (k % 2), 0, __LINE__, "%{$FCALL} unexpectedly propagated an exception"); #else // if defined (_RWSTD_NO_EXCEPTIONS) nread = is.readsome (buf, j); #endif // _RWSTD_NO_EXCEPTIONS ////////////////////////////////////////////////////////////////// // verify that the function returned the expected number of // extracted characters const std::streamsize extracted = sb.pubgptr () - sb.pubeback (); rw_assert (extract == extracted, 0, __LINE__, "%{$FCALL} expected to extract %d chars, got %u; " "initial state = %{Is}, underflow %s at extraction %u", extract, extracted, states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify that the expected number of characters have been // extracted from the stream rw_assert (cbuf + extract == sb.pubgptr (), 0, __LINE__, "%{$FCALL} expected to extract %d chars, got %u; " "initial state = %{Is}, underflow %s at extraction %u", extract, extracted, states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify that the extracted characters match those in the buffer rw_assert (0 == std::char_traits<charT>::compare (buf, cbuf, extract), 0, __LINE__, "%{$FCALL} expected to extract the first %d chars, got %{*Ac}", extract, int (sizeof *buf), buf); ////////////////////////////////////////////////////////////////// // verify that gcount() correctly reflects the number of // characters successfully extracted from the stream rw_assert (extract == is.gcount (), 0, __LINE__, "%{$FCALL}: gcount() == %d, got %d; initial state = %{Is}, " "underflow %s at extraction %u", extract, is.gcount (), states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify the state of the stream object after the function call // expected stream state after the function call is unchanged // (i.e., the initial stream state), except... std::ios_base::iostate expect_state = states [i]; if (!states [i]) { #ifndef _RWSTD_NO_EXCEPTIONS // ...if an extraction is attempted, or even if the first // character on the stream is peeked at, and an exception // is thrown during input, badbit should be set, otherwise // if in_avail() returned -1, eofbit should be set, else // the state should be good if (-2 == l) expect_state = std::ios_base::badbit; else if (l < 0) expect_state = std::ios_base::eofbit; else expect_state = std::ios_base::goodbit; #else // if defined (_RWSTD_NO_EXCEPTIONS) if (l < 0) expect_state = std::ios_base::eofbit; else expect_state = std::ios_base::goodbit; #endif // _RWSTD_NO_EXCEPTIONS } else { // ...if the initial stream state is not good, failbit // must be set expect_state = states [i] | std::ios_base::failbit; } rw_assert (is.rdstate () == expect_state, 0, __LINE__, "%{$FCALL}: rdstate() == %{Is}, got %{Is}; " "extracted %u characters; " "initial state = %{Is}, underflow %s at extraction %u", expect_state, is.rdstate (), extracted, states [i], err_type, k); ++iter; }