blob: 636f453d8d9fdd3ba824f995a8db42da199f07fe [file] [log] [blame]
/***************************************************************************
*
* 21.string.io.cpp - string test exercising lib.string.io
*
* $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.
*
*
**************************************************************************/
#include <string> // for string
#include <cstddef> // for size_t
#include <istream> // for istream
#include <ostream> // for ostream
#include <locale> // for locale
#include <rw_strings.h> // for StringMembers
#include <rw_driver.h> // for rw_test()
#include <rw_allocator.h> // for UserAlloc
#include <rw_char.h> // for rw_expand()
#include <rw_ctype.h> // for UserCtype
#include <rw_new.h> // for bad_alloc, replacement operator new
#include <rw_streambuf.h> // for MyStreambuf
/**************************************************************************/
static const char* const exceptions[] = {
"unknown exception", "ios_base::failure", "bad_alloc", "exception"
};
/**************************************************************************/
// for convenience
#define Good std::ios_base::goodbit
#define Eof std::ios_base::eofbit
#define Fail std::ios_base::failbit
#define Bad std::ios_base::badbit
#define NotGood (Eof | Fail | Bad)
#define Skipws std::ios_base::skipws
#define Left std::ios_base::left
#define Right std::ios_base::right
#define WHITESPACE " \f\n\r\t\v"
const char SYMB_THROW = '!';
// off - width
// size - fmtflags
// off2 - iostate or exceptions mask
// size2 - expected iostate or -1 if not verifyed
// val - expected width
// str - controlled sequence
// arg - sequence in stream
// res - expected result
// bthrow == 0 - off2 is initial stream state
// == 1 - off2 is exceptions mask
// used to exercise
// operator>> (istream&, string&)
static const StringTestCase
extractor_test_cases [] = {
#undef TEST
#define TEST(str, arg, width, flags, state, res, res_width, res_st, bthrow) { \
__LINE__, width, flags, state, res_st, res_width, \
str, sizeof (str) - 1, arg, sizeof (arg) - 1, \
res, sizeof (res) - 1, bthrow \
}
// 1.
// the string argument and stream width should be unchanged when
// the stream's initial state is not good, or the initial state
// is good and skipws is set and the stream's buffer contains only
// whitespace characters or is empty
// +----------------------------------------------- initial string
// | +------------------------------------------ sequence in stream
// | | +------------------------------ stream width
// | | | +-------------------------- stream flags
// | | | | +------------------ stream state
// | | | | | or exceptions
// | | | | | +--------- expected result
// | | | | | | +------- expected width
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +------------+
// | | | | | | | +--+ |
// | | | | | | +--+ | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST1
#define TEST1(str) \
TEST (str, "", 0, 0, Eof, str, 0, Eof, 0), \
TEST (str, "", 1, 0, Fail, str, 1, Fail, 0), \
TEST (str, "", 2, 0, Bad, str, 2, Bad, 0), \
TEST (str, "", 3, Skipws, Eof, str, 3, Eof, 0), \
TEST (str, "", 4, Skipws, Fail, str, 4, Fail, 0), \
TEST (str, "", 5, Skipws, Bad, str, 5, Bad, 0), \
TEST (str, "", 6, Skipws, Good, str, 6, Eof | Fail, 0), \
TEST (str, WHITESPACE, 7, 0, Eof, str, 7, Eof, 0), \
TEST (str, WHITESPACE, 8, 0, Fail, str, 8, Fail, 0), \
TEST (str, WHITESPACE, 9, 0, Bad, str, 9, Bad, 0), \
TEST (str, WHITESPACE, 10, Skipws, Eof, str, 10, Eof, 0), \
TEST (str, WHITESPACE, 11, Skipws, Fail, str, 11, Fail, 0), \
TEST (str, WHITESPACE, 12, Skipws, Bad, str, 12, Bad, 0), \
TEST (str, WHITESPACE, 13, Skipws, Good, str, 13, Eof | Fail, 0), \
TEST (str, "", 14, Skipws, NotGood, str, 14, Eof | Fail, 1), \
TEST (str, WHITESPACE, 15, Skipws, NotGood, str, 15, Eof | Fail, 1)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST1 ("" ),
TEST1 ("ab" ),
TEST1 ("abc" ),
TEST1 ("<U0>" ),
TEST1 ("<U0>@2ab" ),
TEST1 ("a<U0>@2b" ),
TEST1 ("ab<U0>@2" ),
TEST1 ("a<U0>b<U0>@2c"),
TEST1 ("<U0>ab<U0>@2c"),
TEST1 ("x@4096" ),
// 2.
// the string argument should be cleared when the stream's initial
// state is good and skipws is not set and the stream's buffer is
// empty or contains a string which begins with whitespace
// width should be reset to 0, and the stream's state should have
// failbit set
// +----------------------------------------------- initial string
// | +------------------------------------------ sequence in stream
// | | +------------------- stream width
// | | | +--------------- stream flags
// | | | | +------------ stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- expected width
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +-----------------+
// | | | | | | | +-------+ |
// | | | | | | +-----+ | |
// | | | | | +----+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST2
#define TEST2(str) \
TEST (str, "", 0, 0, Good, "", 0 , Eof | Fail, 0), \
TEST (str, "", 10, 0, Good, "", 0 , Eof | Fail, 0), \
TEST (str, WHITESPACE, 0, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE, 2, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE, 20, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc", 0, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc", 2, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc", 10, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc\ndef", 0, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc\ndef", 3, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "abc\ndef", 30, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "<U0>@3", 0, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "<U0>@3", 2, 0, Good, "", 0 , Fail, 0), \
TEST (str, WHITESPACE "<U0>@3", 10, 0, Good, "", 0 , Fail, 0), \
TEST (str, "", 0, 0, NotGood, "", 0 , Eof | Fail, 1), \
TEST (str, "", 10, 0, NotGood, "", 0 , Eof | Fail, 1), \
TEST (str, WHITESPACE, 0, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE, 2, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE, 20, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc", 0, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc", 2, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc", 10, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc\ndef", 0, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc\ndef", 3, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "abc\ndef", 30, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "<U0>@3", 0, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "<U0>@3", 2, 0, NotGood, "", 0 , Fail, 1), \
TEST (str, WHITESPACE "<U0>@3", 10, 0, NotGood, "", 0 , Fail, 1)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST2 ("" ),
TEST2 ("ab" ),
TEST2 ("abc" ),
TEST2 ("<U0>" ),
TEST2 ("<U0>@2ab" ),
TEST2 ("a<U0>@2b" ),
TEST2 ("ab<U0>@2" ),
TEST2 ("a<U0>b<U0>@2c"),
TEST2 ("<U0>ab<U0>@2c"),
TEST2 ("x@4096" ),
// 3.
// the string argument should contain the extracted characters when
// the stream's initial state is good and either
// skipws is clear and the stream's buffer doesn't contain whitespace
// or
// skipws is set
// width should be reset to 0
// +----------------------------------------------- initial string
// | +------------------------------ sequence in stream
// | | +------------------------- stream width
// | | | +------------------ stream flags
// | | | | +----------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- expected width
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +----------+
// | | | | | | | +--------+ |
// | | | | | | +------+ | |
// | | | | | +-----+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST3
#define TEST3(arg, width, flags, res) \
TEST ("", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("ab", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("abc", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("<U0>", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("<U0>@2ab", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("a<U0>@2b", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("ab<U0>@2", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("a<U0>b<U0>@2c", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("<U0>ab<U0>@2c", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("x@4096", arg, width, flags, Good, res, 0, -1, 0), \
TEST ("", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("ab", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("abc", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("<U0>", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("<U0>@2ab", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("a<U0>@2b", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("ab<U0>@2", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("a<U0>b<U0>@2c", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("<U0>ab<U0>@2c", arg, width, flags, NotGood, res, 0, -1, 1), \
TEST ("x@4096", arg, width, flags, NotGood, res, 0, -1, 1)
// +------------------------------------------------- sequence in stream
// | +-------------------- stream width
// | | +---------------- stream flags
// | | | +-------- expected result
// | | | |
// | | | |
// V V V V
TEST3 ("a!bc", 1, 0, "a" ),
TEST3 ("a!bc", 2, 0, "a!" ),
TEST3 ("a!bc", 10, 0, "a!bc"),
TEST3 ("ab!c ", 10, 0, "ab!c"),
TEST3 ("ab!c\f", 10, 0, "ab!c"),
TEST3 ("ab!c\n", 10, 0, "ab!c"),
TEST3 ("ab!c\r", 10, 0, "ab!c"),
TEST3 ("ab!c\t", 10, 0, "ab!c"),
TEST3 ("ab!c\v", 10, 0, "ab!c"),
TEST3 ("a!bc" WHITESPACE, 0, 0, "a!bc"),
TEST3 ("ab!c" WHITESPACE, 2, 0, "ab" ),
TEST3 ("abc!" WHITESPACE, 10, 0, "abc!"),
TEST3 ("abc!", 0, Skipws, "abc!"),
TEST3 ("ab!c", 2, Skipws, "ab" ),
TEST3 ("a!bc", 10, Skipws, "a!bc"),
TEST3 ("abc" WHITESPACE, 0, Skipws, "abc" ),
TEST3 ("abc" WHITESPACE, 2, Skipws, "ab" ),
TEST3 ("abc" WHITESPACE, 10, Skipws, "abc" ),
TEST3 (WHITESPACE "abc", 0, Skipws, "abc" ),
TEST3 (WHITESPACE "abc", 2, Skipws, "ab" ),
TEST3 (WHITESPACE "abc", 30, Skipws, "abc" ),
TEST3 (WHITESPACE "abc" WHITESPACE, 0, Skipws, "abc" ),
TEST3 (WHITESPACE "abc" WHITESPACE, 2, Skipws, "ab" ),
TEST3 (WHITESPACE "abc" WHITESPACE, 30, Skipws, "abc" )
};
/**************************************************************************/
// off - width
// size - fmtflags
// off2 - iostate or exceptions mask
// size2 - expected iostate or -1 if not verifyed
// val - unused
// str - controlled sequence
// arg - sequence in stream
// res - expected result
// bthrow == 0 - off2 is initial stream state
// == 1 - off2 is exceptions mask
// used to exercise
// getline (istream&, string&)
static const StringTestCase
getline_test_cases [] = {
#undef TEST
#define TEST(str, arg, width, flags, state, res, res_width, res_st, bthrow) { \
__LINE__, width, flags, state, res_st, res_width, \
str, sizeof (str) - 1, arg, sizeof (arg) - 1, \
res, sizeof (res) - 1, bthrow \
}
// 1.
// string and width should be unchanged when initial iostate is not good
// +---------------------------------------------- controlled sequence
// | +----------------------------------------- sequence in stream
// | | +-------------------------- stream width
// | | | +---------------------- stream flags
// | | | | +-------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- unused
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +---------+
// | | | | | | | +-----+ |
// | | | | | | +---+ | |
// | | | | | +--+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST1
#define TEST1(str) \
TEST (str, "", 0, 0, Eof, str, 0, Eof, 0), \
TEST (str, "", 1, 0, Fail, str, 0, Fail, 0), \
TEST (str, "", 2, 0, Bad, str, 0, Bad, 0), \
TEST (str, "", 3, Skipws, Eof, str, 0, Eof, 0), \
TEST (str, "", 4, Skipws, Fail, str, 0, Fail, 0), \
TEST (str, "", 5, Skipws, Bad, str, 0, Bad, 0), \
TEST (str, WHITESPACE, 7, 0, Eof, str, 0, Eof, 0), \
TEST (str, WHITESPACE, 8, 0, Fail, str, 0, Fail, 0), \
TEST (str, WHITESPACE, 9, 0, Bad, str, 0, Bad, 0), \
TEST (str, WHITESPACE, 10, Skipws, Eof, str, 0, Eof, 0), \
TEST (str, WHITESPACE, 11, Skipws, Fail, str, 0, Fail, 0), \
TEST (str, WHITESPACE, 12, Skipws, Bad, str, 0, Bad, 0), \
TEST (str, "abc", 13, 0, Eof, str, 0, Eof, 0), \
TEST (str, "x@4096", 14, 0, Fail, str, 0, Fail, 0), \
TEST (str, "<U0>abc<U0>", 15, 0, Bad, str, 0, Bad, 0), \
TEST (str, "abc\ndef", 16, Skipws, Eof, str, 0, Eof, 0), \
TEST (str, " \tabc", 17, Skipws, Fail, str, 0, Fail, 0), \
TEST (str, "\n\n<U0>\n", 18, Skipws, Bad, str, 0, Bad, 0)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST1 ("" ),
TEST1 ("ab" ),
TEST1 ("abc" ),
TEST1 ("<U0>" ),
TEST1 ("<U0>@2ab" ),
TEST1 ("a<U0>@2b" ),
TEST1 ("ab<U0>@2" ),
TEST1 ("a<U0>b<U0>@2c"),
TEST1 ("<U0>ab<U0>@2c"),
TEST1 ("x@4096" ),
// 2.
// string should be erased when initial iostate is good and
// stream empty or contains string which begins from '\n'
// width should be unchanged, iostate should have failbit setted
// +--------------------------------------------- controlled sequence
// | +---------------------------------------- sequence in stream
// | | +-------------------------- stream width
// | | | +---------------------- stream flags
// | | | | +-------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- unused
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +--------------+
// | | | | | | | +----+ |
// | | | | | | +---+ | |
// | | | | | +--+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST2
#define TEST2(str) \
TEST (str, "", 0, Skipws, Good, "", 0, Eof | Fail, 0), \
TEST (str, "", 10, 0, Good, "", 0, Eof | Fail, 0), \
TEST (str, "\n", 0, Skipws, Good, "", 0, Good, 0), \
TEST (str, "\n", 2, 0, Good, "", 0, Good, 0), \
TEST (str, "\nabc", 0, Skipws, Good, "", 0, Good, 0), \
TEST (str, "\nabc", 2, 0, Good, "", 0, Good, 0), \
TEST (str, "\nabc\ndef", 0, Skipws, Good, "", 0, Good, 0), \
TEST (str, "\nabc\ndef", 3, 0, Good, "", 0, Good, 0), \
TEST (str, "\n<U0>@3", 0, Skipws, Good, "", 0, Good, 0), \
TEST (str, "\n<U0>@3", 2, 0, Good, "", 0, Good, 0), \
TEST (str, "", 0, Skipws, NotGood, "", 0, Eof | Fail, 1), \
TEST (str, "", 10, 0, NotGood, "", 0, Eof | Fail, 1), \
TEST (str, "\n", 0, Skipws, NotGood, "", 0, Good, 1), \
TEST (str, "\n", 2, 0, NotGood, "", 0, Good, 1), \
TEST (str, "\nabc", 0, Skipws, NotGood, "", 0, Good, 1), \
TEST (str, "\nabc", 2, 0, NotGood, "", 0, Good, 1), \
TEST (str, "\nabc\ndef", 0, Skipws, NotGood, "", 0, Good, 1), \
TEST (str, "\nabc\ndef", 3, 0, NotGood, "", 0, Good, 1), \
TEST (str, "\n<U0>@3", 0, Skipws, NotGood, "", 0, Good, 1), \
TEST (str, "\n<U0>@3", 2, 0, NotGood, "", 0, Good, 1)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST2 ("" ),
TEST2 ("ab" ),
TEST2 ("abc" ),
TEST2 ("<U0>" ),
TEST2 ("<U0>@2ab" ),
TEST2 ("a<U0>@2b" ),
TEST2 ("ab<U0>@2" ),
TEST2 ("a<U0>b<U0>@2c"),
TEST2 ("<U0>ab<U0>@2c"),
TEST2 ("x@4096" ),
// 3.
// string should be compared with result when initial iostate is good
// and stream string begins from not '\n'
// width should be unchanged
// +----------------------------------------------- controlled sequence
// | +------------------------------ sequence in stream
// | | +------------------------- stream width
// | | | +--------------------- stream flags
// | | | | +------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- unused
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +--------+
// | | | | | | | +------+ |
// | | | | | | +-----+ | |
// | | | | | +---+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST3
#define TEST3(arg, res) \
TEST ("", arg, 0, Skipws, Good, res, 0, -1, 0), \
TEST ("ab", arg, 1, 0, Good, res, 0, -1, 0), \
TEST ("abc", arg, 2, Skipws, Good, res, 0, -1, 0), \
TEST ("<U0>", arg, 3, 0, Good, res, 0, -1, 0), \
TEST ("<U0>@2ab", arg, 4, Skipws, Good, res, 0, -1, 0), \
TEST ("a<U0>@2b", arg, 5, 0, Good, res, 0, -1, 0), \
TEST ("ab<U0>@2", arg, 6, Skipws, Good, res, 0, -1, 0), \
TEST ("a<U0>b<U0>@2c", arg, 7, 0, Good, res, 0, -1, 0), \
TEST ("<U0>ab<U0>@2c", arg, 8, Skipws, Good, res, 0, -1, 0), \
TEST ("x@4096", arg, 9, 0, Good, res, 0, -1, 0), \
TEST ("", arg, 10, Skipws, NotGood, res, 0, -1, 1), \
TEST ("ab", arg, 11, 0, NotGood, res, 0, -1, 1), \
TEST ("abc", arg, 12, Skipws, NotGood, res, 0, -1, 1), \
TEST ("<U0>", arg, 13, 0, NotGood, res, 0, -1, 1), \
TEST ("<U0>@2ab", arg, 14, Skipws, NotGood, res, 0, -1, 1), \
TEST ("a<U0>@2b", arg, 15, 0, NotGood, res, 0, -1, 1), \
TEST ("ab<U0>@2", arg, 16, Skipws, NotGood, res, 0, -1, 1), \
TEST ("a<U0>b<U0>@2c", arg, 17, 0, NotGood, res, 0, -1, 1), \
TEST ("<U0>ab<U0>@2c", arg, 18, Skipws, NotGood, res, 0, -1, 1), \
TEST ("x@4096", arg, 19, 0, NotGood, res, 0, -1, 1)
// +------------------------------------------------- sequence in stream
// | +----------------------- expected result
// | |
// | |
// V V
TEST3 ("ab!c", "ab!c" ),
TEST3 ("a!b\nc", "a!b" ),
TEST3 ("a\n!bc", "a" ),
TEST3 (" !\t\n", " !\t" ),
TEST3 (" \f\r\t\v\n", " \f\r\t\v" ),
TEST3 (" \f\r\n\t\v\n", " \f\r" ),
TEST3 ("<U0>a<U0>b<U0>\n<U0>@2", "<U0>a<U0>b<U0>"),
TEST3 ("<U0>@7", "<U0>@7" ),
TEST3 ("x@4096", "x@4096" ),
TEST3 ("x@4096\nx@4096", "x@4096" )
};
/**************************************************************************/
// off - width
// size - fmtflags
// off2 - iostate or exceptions mask
// size2 - expected iostate or -1 if not verifyed
// val - char delim
// str - controlled sequence
// arg - sequence in stream
// res - expected result
// bthrow == 0 - off2 is initial stream state
// == 1 - off2 is exceptions mask
// used to exercise
// getline (istream&, string&, char)
static const StringTestCase
getline_val_test_cases [] = {
#undef TEST
#define TEST(str, arg, width, flags, state, res, res_width, res_st, bthrow) { \
__LINE__, width, flags, state, res_st, res_width, \
str, sizeof (str) - 1, arg, sizeof (arg) - 1, \
res, sizeof (res) - 1, bthrow \
}
// 1.
// string and width should be unchanged when initial iostate is not good
// +---------------------------------------------- controlled sequence
// | +----------------------------------------- sequence in stream
// | | +-------------------------- stream width
// | | | +---------------------- stream flags
// | | | | +-------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- delim
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +------------+
// | | | | | | | +--------+ |
// | | | | | | +----+ | |
// | | | | | +--+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST1
#define TEST1(str) \
TEST (str, "", 0, 0, Eof, str, '\n', Eof, 0), \
TEST (str, "", 1, 0, Fail, str, '\0', Fail, 0), \
TEST (str, "", 2, 0, Bad, str, '\r', Bad, 0), \
TEST (str, "", 3, Skipws, Eof, str, '\a', Eof, 0), \
TEST (str, "", 4, Skipws, Fail, str, '\b', Fail, 0), \
TEST (str, "", 5, Skipws, Bad, str, '\t', Bad, 0), \
TEST (str, WHITESPACE, 7, 0, Eof, str, '\v', Eof, 0), \
TEST (str, WHITESPACE, 8, 0, Fail, str, 'a', Fail, 0), \
TEST (str, WHITESPACE, 9, 0, Bad, str, ' ', Bad, 0), \
TEST (str, WHITESPACE, 10, Skipws, Eof, str, '1', Eof, 0), \
TEST (str, WHITESPACE, 11, Skipws, Fail, str, '5', Fail, 0), \
TEST (str, WHITESPACE, 12, Skipws, Bad, str, 'w', Bad, 0), \
TEST (str, "abc", 13, 0, Eof, str, 'b', Eof, 0), \
TEST (str, "x@4096", 14, 0, Fail, str, 'x', Fail, 0), \
TEST (str, "<U0>abc<U0>", 15, 0, Bad, str, 'c', Bad, 0), \
TEST (str, "abc\ndef", 16, Skipws, Eof, str, 'e', Eof, 0), \
TEST (str, " \tabc", 17, Skipws, Fail, str, '\t', Fail, 0), \
TEST (str, "\n\n<U0>\n", 18, Skipws, Bad, str, '\0', Bad, 0)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST1 ("" ),
TEST1 ("ab" ),
TEST1 ("abc" ),
TEST1 ("<U0>" ),
TEST1 ("<U0>@2ab" ),
TEST1 ("a<U0>@2b" ),
TEST1 ("ab<U0>@2" ),
TEST1 ("a<U0>b<U0>@2c"),
TEST1 ("<U0>ab<U0>@2c"),
TEST1 ("x@4096" ),
// 2.
// string should be erased when initial iostate is good and
// stream empty or contains string which begins from delim
// width should be unchanged, iostate should have failbit setted
// +--------------------------------------------- controlled sequence
// | +---------------------------------------- sequence in stream
// | | +-------------------------- stream width
// | | | +---------------------- stream flags
// | | | | +-------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- delim
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +-----------------+
// | | | | | | | +-------+ |
// | | | | | | +---+ | |
// | | | | | +--+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST2
#define TEST2(str) \
TEST (str, "", 0, Skipws, Good, "", '\a', Eof | Fail, 0), \
TEST (str, "", 10, 0, Good, "", '\0', Eof | Fail, 0), \
TEST (str, "<U0>", 0, Skipws, Good, "", '\0', Good, 0), \
TEST (str, "\n", 2, 0, Good, "", '\n', Good, 0), \
TEST (str, "\rabc", 0, Skipws, Good, "", '\r', Good, 0), \
TEST (str, "abc", 2, 0, Good, "", 'a', Good, 0), \
TEST (str, "\babc\ndef", 0, Skipws, Good, "", '\b', Good, 0), \
TEST (str, "\tabc\ndef", 3, 0, Good, "", '\t', Good, 0), \
TEST (str, "\v<U0>@3", 0, Skipws, Good, "", '\v', Good, 0), \
TEST (str, " <U0>@3", 2, 0, Good, "", ' ', Good, 0), \
TEST (str, "", 0, Skipws, NotGood, "", '\a', Eof | Fail, 1), \
TEST (str, "", 10, 0, NotGood, "", '\0', Eof | Fail, 1), \
TEST (str, "<U0>", 0, Skipws, NotGood, "", '\0', Good, 1), \
TEST (str, "\n", 2, 0, NotGood, "", '\n', Good, 1), \
TEST (str, "\rabc", 0, Skipws, NotGood, "", '\r', Good, 1), \
TEST (str, "abc", 2, 0, NotGood, "", 'a', Good, 1), \
TEST (str, "\babc\ndef", 0, Skipws, NotGood, "", '\b', Good, 1), \
TEST (str, "\tabc\ndef", 3, 0, NotGood, "", '\t', Good, 1), \
TEST (str, "\v<U0>@3", 0, Skipws, NotGood, "", '\v', Good, 1), \
TEST (str, " <U0>@3", 2, 0, NotGood, "", ' ', Good, 1)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST2 ("" ),
TEST2 ("ab" ),
TEST2 ("abc" ),
TEST2 ("<U0>" ),
TEST2 ("<U0>@2ab" ),
TEST2 ("a<U0>@2b" ),
TEST2 ("ab<U0>@2" ),
TEST2 ("a<U0>b<U0>@2c"),
TEST2 ("<U0>ab<U0>@2c"),
TEST2 ("x@4096" ),
// 3.
// string should be compared with result when initial iostate is good
// and stream string begins from not delim
// width should be unchanged
// +----------------------------------------------- controlled sequence
// | +------------------------------ sequence in stream
// | | +------------------------- stream width
// | | | +--------------------- stream flags
// | | | | +------------- stream state
// | | | | | or exceptions
// | | | | | +-------- expected result
// | | | | | | +----- delim
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +------------+
// | | | | | | | +----------+ |
// | | | | | | +-----+ | |
// | | | | | +---+ | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST3
#define TEST3(arg, delim, res) \
TEST ("", arg, 0, Skipws, Good, res, delim, -1, 0), \
TEST ("ab", arg, 1, 0, Good, res, delim, -1, 0), \
TEST ("abc", arg, 2, Skipws, Good, res, delim, -1, 0), \
TEST ("<U0>", arg, 3, 0, Good, res, delim, -1, 0), \
TEST ("<U0>@2ab", arg, 4, Skipws, Good, res, delim, -1, 0), \
TEST ("a<U0>@2b", arg, 5, 0, Good, res, delim, -1, 0), \
TEST ("ab<U0>@2", arg, 6, Skipws, Good, res, delim, -1, 0), \
TEST ("a<U0>b<U0>@2c", arg, 7, 0, Good, res, delim, -1, 0), \
TEST ("<U0>ab<U0>@2c", arg, 8, Skipws, Good, res, delim, -1, 0), \
TEST ("x@4096", arg, 9, 0, Good, res, delim, -1, 0), \
TEST ("", arg, 10, Skipws, NotGood, res, delim, -1, 1), \
TEST ("ab", arg, 11, 0, NotGood, res, delim, -1, 1), \
TEST ("abc", arg, 12, Skipws, NotGood, res, delim, -1, 1), \
TEST ("<U0>", arg, 13, 0, NotGood, res, delim, -1, 1), \
TEST ("<U0>@2ab", arg, 14, Skipws, NotGood, res, delim, -1, 1), \
TEST ("a<U0>@2b", arg, 15, 0, NotGood, res, delim, -1, 1), \
TEST ("ab<U0>@2", arg, 16, Skipws, NotGood, res, delim, -1, 1), \
TEST ("a<U0>b<U0>@2c", arg, 17, 0, NotGood, res, delim, -1, 1), \
TEST ("<U0>ab<U0>@2c", arg, 18, Skipws, NotGood, res, delim, -1, 1), \
TEST ("x@4096", arg, 19, 0, NotGood, res, delim, -1, 1)
// +------------------------------------------------- sequence in stream
// | +----------------------- delim
// | | +----------------- expected result
// | | |
// | | |
// V V V
TEST3 ("ab!c", '\t', "ab!c" ),
TEST3 ("a!b<U0>c", '\0', "a!b" ),
TEST3 ("a\n!bc", 'b', "a\n!" ),
TEST3 (" \t\n", '\n', " \t" ),
TEST3 (" \f\r\t\v\n", '\v', " \f\r\t" ),
TEST3 (" \f\r\n\t\v\n", '\r', " \f" ),
TEST3 ("<U0>a<U0>b<U0>\n<U0>@2", 'b', "<U0>a<U0>"),
TEST3 ("<U0>@7", '1', "<U0>@7" ),
TEST3 ("x@4096", ' ', "x@4096" ),
TEST3 ("x@4096yx@4096", 'y', "x@4096" )
};
/**************************************************************************/
// off - width
// size - fmtflags
// off2 - iostate or exceptions mask
// size2 - expected iostate or -1 if not verifyed
// val - expected width
// str - controlled sequence
// arg_len - size of streambuf
// res - expected result
// bthrow == 0 - off2 is initial stream state
// == 1 - off2 is exceptions mask
// used to exercise
// operator<< (ostream&, const string&)
static const StringTestCase
inserter_test_cases [] = {
#undef TEST
#define TEST(str, arg, width, flags, state, res, res_width, res_st, bthrow) { \
__LINE__, width, flags, state, res_st, res_width, \
str, sizeof (str) - 1, 0, arg, res, sizeof (res) - 1, bthrow \
}
// 1. if initial state is not good then width should be
// unchanged and no data in output stream
// +----------------------------------------- controlled sequence
// | +------------------------------------ size of streambuf
// | | +------------------------- stream width
// | | | +--------------------- stream flags
// | | | | +------------- stream state
// | | | | | or exceptions
// | | | | | +------- expected result
// | | | | | | +----- expected width
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +-------+
// | | | | | | | +---+ |
// | | | | | | +-+ | |
// | | | | | | | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST1
#define TEST1(str) \
TEST (str, 0, 0, 0, Eof, "", 0, Eof, 0), \
TEST (str, 0, 1, 0, Fail, "", 1, Fail, 0), \
TEST (str, 0, 2, 0, Bad, "", 2, Bad, 0)
// +----------------------------------------- controlled sequence
// |
// |
// V
TEST1 ("" ),
TEST1 ("ab" ),
TEST1 ("abc" ),
TEST1 ("<U0>" ),
TEST1 ("<U0>@2ab" ),
TEST1 ("a<U0>@2b" ),
TEST1 ("ab<U0>@2" ),
TEST1 ("a<U0>b<U0>@2c"),
TEST1 ("<U0>ab<U0>@2c"),
TEST1 ("x@4096" ),
// 2. if initial state is good then:
// if stream has not enough size to get string then badbit should be set
// width should be 0
// +---------------------------------------- controlled sequence
// | +----------------------------------- size of streambuf
// | | +------------------------------ stream width
// | | | +----------------------- stream flags
// | | | | +---------------- stream state
// | | | | | or exceptions
// | | | | | +------- expected result
// | | | | | | +----- expected width
// | | | | | | | +--- expected state
// | | | | | | | | +- exception info:
// | | | | | | | | | 0 - no exception
// | | | | | | | | | 1 - ios_base::failure
// | | | | | | | | | -1 - exc. safety
// | | | | | | | | |
// | | | | | | | | +-----------------+
// | | | | | | | +-----------+ |
// | | | | | | +--+ | |
// | | | | | | | | |
// | | | | | | | | |
// V V V V V V V V V
#undef TEST2
#define TEST2(str, arg, width, flags, res, res_width, res_st) \
TEST (str, arg, width, flags, Good, res, res_width, res_st, 0), \
TEST (str, arg, width, flags, NotGood, res, res_width, res_st, 1)
// +------------------------------------------------ controlled sequence
// | +------------------------------- size of streambuf
// | | +------------------------- stream width
// | | | +------------------- stream flags
// | | | | +------------ expected result
// | | | | | +----- expected width
// | | | | | | +-- expected state
// | | | | | | |
// | | | | | | +---------------+
// | | | | | +------------+ |
// | | | | | | |
// V V V V V V V
TEST2 ("", 0, 0, 0, "", 0, Good),
TEST2 ("", 0, 0, Right, "", 0, Good),
TEST2 ("", 0, 0, Left, "", 0, Good),
TEST2 ("", 20, 10, 0, " @10", 0, Good),
TEST2 ("", 20, 10, Right, " @10", 0, Good),
TEST2 ("", 20, 10, Left, " @10", 0, Good),
TEST2 ("", 5, 10, 0, " @5", 0, Bad ),
TEST2 ("", 5, 10, Right, " @5", 0, Bad ),
TEST2 ("", 5, 10, Left, " @5", 0, Bad ),
TEST2 (" @10", 20, 10, 0, " @10", 0, Good),
TEST2 (" @10", 20, 10, Right, " @10", 0, Good),
TEST2 (" @10", 20, 10, Left, " @10", 0, Good),
TEST2 ("abc def", 20, 0, 0, "abc def", 0, Good),
TEST2 ("abc def", 20, 0, Right, "abc def", 0, Good),
TEST2 ("abc def", 20, 0, Left, "abc def", 0, Good),
TEST2 ("abc def", 5, 0, 0, "abc d", 0, Bad ),
TEST2 ("abc def", 5, 0, Right, "abc d", 0, Bad ),
TEST2 ("abc def", 5, 0, Left, "abc d", 0, Bad ),
TEST2 ("abc def", 20, 5, 0, "abc def", 0, Good),
TEST2 ("abc def", 20, 5, Right, "abc def", 0, Good),
TEST2 ("abc def", 20, 5, Left, "abc def", 0, Good),
TEST2 ("abc def", 20, 10, 0, " abc def", 0, Good),
TEST2 ("abc def", 20, 10, Right, " abc def", 0, Good),
TEST2 ("abc def", 20, 10, Left, "abc def ", 0, Good),
TEST2 ("<U0>", 20, 10, 0, " @9<U0>", 0, Good),
TEST2 ("<U0>", 20, 10, Right, " @9<U0>", 0, Good),
TEST2 ("<U0>", 20, 10, Left, "<U0> @9", 0, Good),
TEST2 ("<U0>ab<U0>@2c", 20, 10, 0, " @4<U0>ab<U0>@2c", 0, Good),
TEST2 ("<U0>ab<U0>@2c", 20, 10, Right, " @4<U0>ab<U0>@2c", 0, Good),
TEST2 ("<U0>ab<U0>@2c", 20, 10, Left, "<U0>ab<U0>@2c @4", 0, Good),
TEST2 ("x@4096", 4096, 10, 0, "x@4096", 0, Good),
TEST2 ("x@4096", 4096, 10, Right, "x@4096", 0, Good),
TEST2 ("x@4096", 4096, 10, Left, "x@4096", 0, Good),
TEST2 ("x@4096", 4097, 4097, 0, " x@4096", 0, Good),
TEST2 ("x@4096", 4097, 4097, Right, " x@4096", 0, Good),
TEST2 ("x@4096", 4097, 4097, Left, "x@4096 ", 0, Good)
};
/**************************************************************************/
template <class charT, class Traits, class Allocator>
void test_io (charT*, Traits*, Allocator*,
const StringTestCaseData<charT> &tdata)
{
typedef std::basic_string <charT, Traits, Allocator> String;
typedef MyStreambuf<charT, Traits> Streambuf;
typedef std::basic_ios<charT, Traits> BasicIos;
typedef std::basic_istream<charT, Traits> Istream;
typedef std::basic_ostream<charT, Traits> Ostream;
typedef std::ios_base::fmtflags Fmtflags;
typedef std::ios_base::iostate Iostate;
const StringFunc &func = tdata.func_;
const StringTestCase &tcase = tdata.tcase_;
bool test_inserter = func.which_ == StringIds::inserter_ostream_cstr;
// construct the string object
String str (tdata.str_, tdata.strlen_);
// construct a const reference to the string object
// for tests exercising output
const String& cstr (str);
static const std::size_t BUFSIZE = 256;
static char arg_buf [BUFSIZE];
std::size_t arg_len = 0;
const char* arg = rw_expand (arg_buf, tcase.arg, tcase.arg_len, &arg_len);
// prepare arrays of indexes on which force the exception throwing
const charT* arg_throw = test_inserter ? tdata.str_ : tdata.arg_;
const std::size_t arg_throw_len =
test_inserter ? tdata.strlen_ : tdata.arglen_;
std::size_t* throw_on = new std::size_t [arg_throw_len + 1];
std::size_t pthrow = 0;
for (std::size_t k = 0; k < arg_throw_len; ++k) {
if (1 == rw_match (&SYMB_THROW, arg_throw + k, 1))
throw_on [pthrow++] = k + 1;
}
throw_on [pthrow] = NPOS;
// construct ctype facet to install in each stream's locale
// (the facet's lifetime must exceed that of the locale in
// which it is installed, which might include both the stream
// and the stream's streambuf)
const UserCtype<charT> ctyp (1);
// set the initial formatting flags in both streams
const Fmtflags flags = Fmtflags (tcase.size);
// save the state of the const string object before the call
// to any (changes to the state of the object after a call)
const StringState cstr_state (rw_get_string_state (cstr));
// Xsgetn, Sync, Xsputn
std::size_t throw_count [] = { 1, 1, 1 };
std::size_t throw_inx = 0;
while (1) {
Streambuf inbuf (arg, arg_len, Throw | Underflow | Sync | Xsgetn, -1);
Streambuf outbuf (std::streamsize (tcase.arg_len),
Throw | Overflow | Sync | Xsputn, -1);
Streambuf& sbuf = test_inserter ? outbuf : inbuf;
#ifndef _RWSTD_NO_EXCEPTIONS
// (name of) expected and caught exception
const char* expected = 0;
const char* caught = 0;
if (1 == tcase.bthrow) {
expected = exceptions [1]; // ios_base::failure
}
else if (0 == tcase.bthrow) {
// set on which call of which method to throw
sbuf.throw_when_ [sbuf.memfun_inx (
test_inserter ? Overflow : Underflow) ] =
int (throw_on [throw_inx]);
sbuf.throw_when_ [sbuf.memfun_inx (Xsgetn)] =
int (throw_count [0]);
sbuf.throw_when_ [sbuf.memfun_inx (Sync)] =
int (throw_count [1]);
sbuf.throw_when_ [sbuf.memfun_inx (Xsputn)] =
int (throw_count [2]);
}
else {
// exceptions disabled for this test case
}
#else // if defined (_RWSTD_NO_EXCEPTIONS)
if (tcase.bthrow)
return;
#endif // _RWSTD_NO_EXCEPTIONS
// construct both stream objects even though only one will be used
Istream is (&inbuf);
Ostream os (&outbuf);
// base referes to the basic_ios subobject of the stream used in
// each test case (to avoid unnecessarily manipulating both streams)
BasicIos &strm = test_inserter ? (BasicIos&)os : (BasicIos&)is;
// install std::ctype<UserChar> facet
strm.imbue (std::locale (strm.getloc (), &ctyp));
// set the initial width of both streams
strm.width (tcase.off);
strm.flags (flags);
const Iostate state = Iostate (tcase.off2);
if (tcase.bthrow) {
// set exception bits leaving the initial stream state good
strm.exceptions (state);
}
else {
// set the initial stream state leaving exceptions clear
strm.clear (state);
}
// start checking for memory leaks
rw_check_leaks (str.get_allocator ());
bool streambuf_threw = false;
try {
// the offset of the address of the returned reference
// from the address of the stream object argument (the
// two must be the same)
std::ptrdiff_t ret_off = 0;
try {
switch (func.which_) {
case StringIds::extractor_istream_str:
ret_off = &is - &(is >> str);
break;
case StringIds::getline_istream_str:
ret_off = &is - &std::getline (is, str);
break;
case StringIds::getline_istream_str_val: {
const charT delim = make_char (tcase.val, (charT*)0);
ret_off = &is - &std::getline (is, str, delim);
break;
}
case StringIds::inserter_ostream_cstr:
ret_off = &os - &(os << cstr);
break;
default:
RW_ASSERT (!"test logic error: unknown io overload");
return;
}
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (std::ios_base::failure& ex) {
caught = exceptions [1];
rw_assert (caught == expected, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s,%{:}"
"unexpectedly%{;} caught std::%s(%#s)",
__LINE__, 0 != expected, expected, caught,
ex.what ());
}
catch (...) {
caught = exceptions [0];
rw_assert (0, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s,%{:}"
"unexpectedly%{;} caught %s",
__LINE__, 0 != expected, expected, caught);
}
#endif // _RWSTD_NO_EXCEPTIONS
const std::streamsize ret_width = strm.width ();
const Iostate ret_state = strm.rdstate ();
const charT* ret_str = str.data ();
std::size_t ret_sz = str.size ();
if (test_inserter) {
ret_str = outbuf.pubpbase ();
ret_sz = outbuf.pubepptr () - ret_str;
}
streambuf_threw = None != sbuf.threw_;
if (streambuf_threw) {
if (Overflow == sbuf.threw_ || Underflow == sbuf.threw_)
throw_inx++;
if (Xsgetn == sbuf.threw_)
throw_count [0] ++;
if (Sync == sbuf.threw_)
throw_count [1] ++;
if (Xsputn == sbuf.threw_)
throw_count [2] ++;
}
// character width (for convenience)
static const int cwidth = sizeof (charT);
// verify that the reference returned from the function
// refers to the passed stream object
bool success = 0 == ret_off;
rw_assert (success, 0, tcase.line,
"line %d. %{$FUNCALL} returned invalid reference, "
"offset is %td", __LINE__, ret_off);
if (!streambuf_threw) {
// verify the width
const std::streamsize width =
func.which_ == StringIds::getline_istream_str
|| func.which_ == StringIds::getline_istream_str_val
#ifndef _RWSTD_NO_EXT_KEEP_WIDTH_ON_FAILURE
|| ( func.which_ == StringIds::inserter_ostream_cstr
&& ret_state != Good)
#endif // _RWSTD_NO_EXT_KEEP_WIDTH_ON_FAILURE
? tcase.off : tcase.val;
success = width == ret_width;
rw_assert (success, 0, tcase.line,
"line %d. %{$FUNCALL}: expected width() == %td, "
"got %td", __LINE__, width, ret_width);
}
// tcase.size2 is the expected iostate
if (0 <= tcase.size2) {
// verify the iostate
const Iostate res_state =
streambuf_threw ? Bad : Iostate (tcase.size2);
success = res_state ?
(res_state == (ret_state & res_state)) : (0 == ret_state);
rw_assert (success, 0, tcase.line,
"line %d. %{$FUNCALL}: expected rdstate() "
"== %{Is}, got %{Is}",
__LINE__, res_state, ret_state);
}
if ( !streambuf_threw
|| Overflow == sbuf.threw_ || Underflow == sbuf.threw_) {
std::size_t res_sz = streambuf_threw ?
sbuf.throw_when_ [sbuf.memfun_inx (sbuf.threw_)] - 1 :
tdata.reslen_;
// verify that strings length are equal
success = res_sz == ret_sz;
rw_assert (success, 0, tcase.line,
"line %d. %{$FUNCALL}: expected %{/*.*Gs} with "
"length %zu, got %{/*.*Gs} with length %zu",
__LINE__,
cwidth, int (res_sz), tdata.res_, res_sz,
cwidth, int (ret_sz), ret_str, ret_sz);
if (res_sz == ret_sz) {
// if the result length matches the expected length
// (and only then), also verify that the modified
// string matches the expected result
const std::size_t match = rw_match (tcase.res,
ret_str, ret_sz);
success = match == res_sz;
rw_assert (success, 0, tcase.line,
"line %d. %{$FUNCALL}: expected %{/*.*Gs}, "
"got %{/*.*Gs}, difference at off %zu",
__LINE__, cwidth, int (res_sz), tdata.res_,
cwidth, int (ret_sz), ret_str, match);
}
}
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (const std::bad_alloc &ex) {
caught = exceptions [2];
rw_assert (0, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s,%{:}"
"unexpectedly%{;} caught std::%s(%#s)",
__LINE__, 0 != expected, expected, caught, ex.what ());
}
catch (const std::exception &ex) {
caught = exceptions [3];
rw_assert (0, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s,%{:}"
"unexpectedly%{;} caught std::%s(%#s)",
__LINE__, 0 != expected, expected, caught, ex.what ());
}
catch (...) {
caught = exceptions [0];
rw_assert (0, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s,%{:}"
"unexpectedly%{;} caught %s",
__LINE__, 0 != expected, expected, caught);
}
#endif // _RWSTD_NO_EXCEPTIONS
// FIXME: verify the number of blocks the function call
// is expected to allocate and detect any memory leaks
rw_check_leaks (str.get_allocator (), tcase.line,
std::size_t (-1), std::size_t (-1));
if (streambuf_threw && 0 == tcase.bthrow) {
// call the function again until streambuf methods
// not throws the exception
continue;
}
else if (1 < tcase.bthrow) {
rw_assert (caught == expected, 0, tcase.line,
"line %d. %{$FUNCALL} %{?}expected %s, caught %s"
"%{:}unexpectedly caught %s%{;}",
__LINE__, 0 != expected, expected, caught, caught);
}
break;
}
if (StringIds::fid_inserter == (StringIds::fid_mask & int (func.which_))) {
// verify that const string object was not modified during
// the call to the inserter (input functions may, obviously,
// modify it)
cstr_state.assert_equal (rw_get_string_state (cstr),
__LINE__, tcase.line, "call");
}
if (arg != arg_buf)
delete[] arg;
arg = 0;
if (throw_on)
delete[] throw_on;
}
/**************************************************************************/
DEFINE_STRING_TEST_FUNCTIONS (test_io);
int main (int argc, char** argv)
{
static const StringTest
tests [] = {
#undef TEST
#define TEST(gsig, sig) { \
gsig, sig ## _test_cases, \
sizeof sig ## _test_cases / sizeof *sig ## _test_cases \
}
TEST (StringIds::extractor_istream_str, extractor),
TEST (StringIds::inserter_ostream_cstr, inserter),
TEST (StringIds::getline_istream_str, getline),
TEST (StringIds::getline_istream_str_val, getline_val)
};
const std::size_t test_count = sizeof tests / sizeof *tests;
return rw_run_string_test (argc, argv, __FILE__,
"lib.string.io",
test_io_func_array, tests, test_count);
}