123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- // (C) Copyright Frank Birbacher 2007
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
- // See http://www.boost.org/libs/iostreams for documentation.
- #include <boost/config.hpp>
- #include <boost/iostreams/categories.hpp> // tags.
- #include <boost/iostreams/detail/ios.hpp> // openmode, seekdir, int types.
- #include <boost/iostreams/detail/error.hpp>
- #include <boost/iostreams/positioning.hpp>
- #include <boost/iostreams/stream.hpp>
- #include <boost/test/test_tools.hpp>
- #include <boost/test/unit_test.hpp>
- using boost::iostreams::detail::bad_read;
- using boost::iostreams::detail::bad_seek;
- using boost::iostreams::detail::bad_write;
- using boost::iostreams::seekable_device_tag;
- using boost::iostreams::stream;
- using boost::iostreams::stream_offset;
- using boost::unit_test::test_suite;
- /*
- * This test unit uses a custom device to trigger errors. The device supports
- * input, output, and seek according to the SeekableDevice concept. And each
- * of the required functions throw a special detail::bad_xxx exception. This
- * should trigger the iostreams::stream to set the badbit status flag.
- * Additionally the exception can be propagated to the caller if the exception
- * mask of the stream allows exceptions.
- *
- * The stream offers four different functions: read, write, seekg, and seekp.
- * Each of them is tested with three different error reporting concepts:
- * test by reading status flags, test by propagated exception, and test by
- * calling std::ios_base::exceptions when badbit is already set.
- *
- * In each case all of the status checking functions of a stream are checked.
- *
- * MSVCPRT (Visual Studio 2017, at least) does not perform exception
- * handling in the seek methods (confirmed by inspecting sources).
- *
- * CYGWIN (with gcc-7.3.0) does not behave properly on the throw_delayed cases.
- */
- //------------------Definition of error_device--------------------------------//
- // Device whose member functions throw
- struct error_device {
- typedef char char_type;
- typedef seekable_device_tag category;
- error_device(char const*) {}
- std::streamsize read(char_type*, std::streamsize)
- {
- throw bad_read();
- }
- std::streamsize write(const char_type*, std::streamsize)
- {
- throw bad_write();
- }
- std::streampos seek(stream_offset, BOOST_IOS::seekdir)
- {
- throw bad_seek();
- }
- };
- typedef stream<error_device> test_stream;
- //------------------Stream state tester---------------------------------------//
- void check_stream_for_badbit(const std::iostream& str)
- {
- BOOST_CHECK_MESSAGE(!str.good(), "stream still good");
- BOOST_CHECK_MESSAGE(!str.eof(), "eofbit set but not expected");
- BOOST_CHECK_MESSAGE(str.bad(), "stream did not set badbit");
- BOOST_CHECK_MESSAGE(str.fail(), "stream did not fail");
- BOOST_CHECK_MESSAGE(str.operator ! (),
- "stream does not report failure by operator !");
- BOOST_CHECK_MESSAGE(false == static_cast<bool>(str),
- "stream does not report failure by operator void* or bool");
- }
- //------------------Test case generators--------------------------------------//
- template<void (*const function)(std::iostream&)>
- struct wrap_nothrow {
- static void execute()
- {
- test_stream stream("foo");
- BOOST_CHECK_NO_THROW( function(stream) );
- check_stream_for_badbit(stream);
- }
- };
- template<void (*const function)(std::iostream&)>
- struct wrap_throw {
- static void execute()
- {
- typedef std::ios_base ios;
- test_stream stream("foo");
-
- stream.exceptions(ios::failbit | ios::badbit);
- BOOST_CHECK_THROW( function(stream), std::exception );
-
- check_stream_for_badbit(stream);
- }
- };
- template<void (*const function)(std::iostream&)>
- struct wrap_throw_delayed {
- static void execute()
- {
- typedef std::ios_base ios;
- test_stream stream("foo");
-
- function(stream);
- BOOST_CHECK_THROW(
- stream.exceptions(ios::failbit | ios::badbit),
- ios::failure
- );
-
- check_stream_for_badbit(stream);
- }
- };
- //------------------Stream operations that throw------------------------------//
- void test_read(std::iostream& str)
- {
- char data[10];
- str.read(data, 10);
- }
- void test_write(std::iostream& str)
- {
- char data[10] = {0};
- str.write(data, 10);
- //force use of streambuf
- str.flush();
- }
- void test_seekg(std::iostream& str)
- {
- str.seekg(10);
- }
- void test_seekp(std::iostream& str)
- {
- str.seekp(10);
- }
- test_suite* init_unit_test_suite(int, char* [])
- {
- test_suite* test = BOOST_TEST_SUITE("stream state test");
-
- test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_read>::execute));
- test->add(BOOST_TEST_CASE(&wrap_throw <&test_read>::execute));
- #ifndef __CYGWIN__
- test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_read>::execute));
- #endif
-
- test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_write>::execute));
- test->add(BOOST_TEST_CASE(&wrap_throw <&test_write>::execute));
- #ifndef __CYGWIN__
- test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_write>::execute));
- #endif
-
- #ifndef BOOST_MSVC
- test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekg>::execute));
- test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekg>::execute));
- #ifndef __CYGWIN__
- test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekg>::execute));
- #endif
-
- test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekp>::execute));
- test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekp>::execute));
- #ifndef __CYGWIN__
- test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekp>::execute));
- #endif
- #endif // BOOST_MSVC
- return test;
- }
|