1// (C) Copyright Frank Birbacher 2007
2// Distributed under the Boost Software License, Version 1.0. (See accompanying
3// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4
5// See http://www.boost.org/libs/iostreams for documentation.
6
7#include <boost/config.hpp>
8#include <boost/iostreams/categories.hpp> // tags.
9#include <boost/iostreams/detail/ios.hpp> // openmode, seekdir, int types.
10#include <boost/iostreams/detail/error.hpp>
11#include <boost/iostreams/positioning.hpp>
12#include <boost/iostreams/stream.hpp>
13#include <boost/test/test_tools.hpp>
14#include <boost/test/unit_test.hpp>
15
16using boost::iostreams::detail::bad_read;
17using boost::iostreams::detail::bad_seek;
18using boost::iostreams::detail::bad_write;
19using boost::iostreams::seekable_device_tag;
20using boost::iostreams::stream;
21using boost::iostreams::stream_offset;
22using boost::unit_test::test_suite;
23
24/*
25 * This test unit uses a custom device to trigger errors. The device supports
26 * input, output, and seek according to the SeekableDevice concept. And each
27 * of the required functions throw a special detail::bad_xxx exception. This
28 * should trigger the iostreams::stream to set the badbit status flag.
29 * Additionally the exception can be propagated to the caller if the exception
30 * mask of the stream allows exceptions.
31 *
32 * The stream offers four different functions: read, write, seekg, and seekp.
33 * Each of them is tested with three different error reporting concepts:
34 * test by reading status flags, test by propagated exception, and test by
35 * calling std::ios_base::exceptions when badbit is already set.
36 *
37 * In each case all of the status checking functions of a stream are checked.
38 *
39 * MSVCPRT (Visual Studio 2017, at least) does not perform exception
40 * handling in the seek methods (confirmed by inspecting sources).
41 *
42 * CYGWIN (with gcc-7.3.0) does not behave properly on the throw_delayed cases.
43 */
44
45//------------------Definition of error_device--------------------------------//
46
47// Device whose member functions throw
48struct error_device {
49 typedef char char_type;
50 typedef seekable_device_tag category;
51 error_device(char const*) {}
52 std::streamsize read(char_type*, std::streamsize)
53 {
54 throw bad_read();
55 }
56 std::streamsize write(const char_type*, std::streamsize)
57 {
58 throw bad_write();
59 }
60 std::streampos seek(stream_offset, BOOST_IOS::seekdir)
61 {
62 throw bad_seek();
63 }
64};
65
66typedef stream<error_device> test_stream;
67
68//------------------Stream state tester---------------------------------------//
69
70void check_stream_for_badbit(const std::iostream& str)
71{
72 BOOST_CHECK_MESSAGE(!str.good(), "stream still good");
73 BOOST_CHECK_MESSAGE(!str.eof(), "eofbit set but not expected");
74 BOOST_CHECK_MESSAGE(str.bad(), "stream did not set badbit");
75 BOOST_CHECK_MESSAGE(str.fail(), "stream did not fail");
76 BOOST_CHECK_MESSAGE(str.operator ! (),
77 "stream does not report failure by operator !");
78 BOOST_CHECK_MESSAGE(false == static_cast<bool>(str),
79 "stream does not report failure by operator void* or bool");
80}
81
82//------------------Test case generators--------------------------------------//
83
84template<void (*const function)(std::iostream&)>
85struct wrap_nothrow {
86 static void execute()
87 {
88 test_stream stream("foo");
89 BOOST_CHECK_NO_THROW( function(stream) );
90 check_stream_for_badbit(str: stream);
91 }
92};
93
94template<void (*const function)(std::iostream&)>
95struct wrap_throw {
96 static void execute()
97 {
98 typedef std::ios_base ios;
99 test_stream stream("foo");
100
101 stream.exceptions(except: ios::failbit | ios::badbit);
102 BOOST_CHECK_THROW( function(stream), std::exception );
103
104 check_stream_for_badbit(str: stream);
105 }
106};
107
108template<void (*const function)(std::iostream&)>
109struct wrap_throw_delayed {
110 static void execute()
111 {
112 typedef std::ios_base ios;
113 test_stream stream("foo");
114
115 function(stream);
116 BOOST_CHECK_THROW(
117 stream.exceptions(ios::failbit | ios::badbit),
118 ios::failure
119 );
120
121 check_stream_for_badbit(str: stream);
122 }
123};
124
125//------------------Stream operations that throw------------------------------//
126
127void test_read(std::iostream& str)
128{
129 char data[10];
130 str.read(s: data, n: 10);
131}
132
133void test_write(std::iostream& str)
134{
135 char data[10] = {0};
136 str.write(s: data, n: 10);
137 //force use of streambuf
138 str.flush();
139}
140
141void test_seekg(std::iostream& str)
142{
143 str.seekg(10);
144}
145
146void test_seekp(std::iostream& str)
147{
148 str.seekp(10);
149}
150
151test_suite* init_unit_test_suite(int, char* [])
152{
153 test_suite* test = BOOST_TEST_SUITE("stream state test");
154
155 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_read>::execute));
156 test->add(BOOST_TEST_CASE(&wrap_throw <&test_read>::execute));
157#ifndef __CYGWIN__
158 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_read>::execute));
159#endif
160
161 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_write>::execute));
162 test->add(BOOST_TEST_CASE(&wrap_throw <&test_write>::execute));
163#ifndef __CYGWIN__
164 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_write>::execute));
165#endif
166
167// MSSTL and libc++ don't handle exceptions from seekg correctly
168#if !defined(_CPPLIB_VER) && !defined(_LIBCPP_VERSION)
169
170 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekg>::execute));
171 test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekg>::execute));
172#ifndef __CYGWIN__
173 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekg>::execute));
174#endif
175
176#endif // !defined(_CPPLIB_VER) && !defined(_LIBCPP_VERSION)
177
178// Since C++11, seekp does not catch exceptions
179#if 0
180
181 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekp>::execute));
182 test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekp>::execute));
183#ifndef __CYGWIN__
184 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekp>::execute));
185#endif
186
187#endif
188
189 return test;
190}
191

source code of boost/libs/iostreams/test/stream_state_test.cpp