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/iostreams/categories.hpp> // tags.
8 #include <boost/iostreams/detail/ios.hpp> // openmode, seekdir, int types.
9 #include <boost/iostreams/detail/error.hpp>
10 #include <boost/iostreams/positioning.hpp>
11 #include <boost/iostreams/stream.hpp>
12 #include <boost/test/test_tools.hpp>
13 #include <boost/test/unit_test.hpp>
14
15 using namespace boost::iostreams;
16 using boost::unit_test::test_suite;
17
18 /*
19 * This test unit uses a custom device to trigger errors. The device supports
20 * input, output, and seek according to the SeekableDevice concept. And each
21 * of the required functions throw a special detail::bad_xxx exception. This
22 * should trigger the iostreams::stream to set the badbit status flag.
23 * Additionally the exception can be propagated to the caller if the exception
24 * mask of the stream allows exceptions.
25 *
26 * The stream offers four different functions: read, write, seekg, and seekp.
27 * Each of them is tested with three different error reporting concepts:
28 * test by reading status flags, test by propagated exception, and test by
29 * calling std::ios_base::exceptions when badbit is already set.
30 *
31 * In each case all of the status checking functions of a stream are checked.
32 */
33
34 //------------------Definition of error_device--------------------------------//
35
36 // Device whose member functions throw
37 struct error_device {
38 typedef char char_type;
39 typedef seekable_device_tag category;
error_deviceerror_device40 error_device(char const*) {}
readerror_device41 std::streamsize read(char_type*, std::streamsize)
42 {
43 throw detail::bad_read();
44 }
writeerror_device45 std::streamsize write(const char_type*, std::streamsize)
46 {
47 throw detail::bad_write();
48 }
seekerror_device49 std::streampos seek(stream_offset, BOOST_IOS::seekdir)
50 {
51 throw detail::bad_seek();
52 }
53 };
54
55 typedef stream<error_device> test_stream;
56
57 //------------------Stream state tester---------------------------------------//
58
check_stream_for_badbit(std::iostream & str)59 void check_stream_for_badbit(std::iostream& str)
60 {
61 BOOST_CHECK_MESSAGE(!str.good(), "stream still good");
62 BOOST_CHECK_MESSAGE(!str.eof(), "eofbit set but not expected");
63 BOOST_CHECK_MESSAGE(str.bad(), "stream did not set badbit");
64 BOOST_CHECK_MESSAGE(str.fail(), "stream did not fail");
65 BOOST_CHECK_MESSAGE(str.operator ! (),
66 "stream does not report failure by operator !");
67 BOOST_CHECK_MESSAGE(0 == str.operator void* (),
68 "stream does not report failure by operator void*");
69 }
70
71 //------------------Test case generators--------------------------------------//
72
73 template<void (*const function)(std::iostream&)>
74 struct wrap_nothrow {
executewrap_nothrow75 static void execute()
76 {
77 test_stream stream("foo");
78 BOOST_CHECK_NO_THROW( function(stream) );
79 check_stream_for_badbit(stream);
80 }
81 };
82
83 template<void (*const function)(std::iostream&)>
84 struct wrap_throw {
executewrap_throw85 static void execute()
86 {
87 typedef std::ios_base ios;
88 test_stream stream("foo");
89
90 stream.exceptions(ios::failbit | ios::badbit);
91 BOOST_CHECK_THROW( function(stream), std::exception );
92
93 check_stream_for_badbit(stream);
94 }
95 };
96
97 template<void (*const function)(std::iostream&)>
98 struct wrap_throw_delayed {
executewrap_throw_delayed99 static void execute()
100 {
101 typedef std::ios_base ios;
102 test_stream stream("foo");
103
104 function(stream);
105 BOOST_CHECK_THROW(
106 stream.exceptions(ios::failbit | ios::badbit),
107 ios::failure
108 );
109
110 check_stream_for_badbit(stream);
111 }
112 };
113
114 //------------------Stream operations that throw------------------------------//
115
test_read(std::iostream & str)116 void test_read(std::iostream& str)
117 {
118 char data[10];
119 str.read(data, 10);
120 }
121
test_write(std::iostream & str)122 void test_write(std::iostream& str)
123 {
124 char data[10] = {0};
125 str.write(data, 10);
126 //force use of streambuf
127 str.flush();
128 }
129
test_seekg(std::iostream & str)130 void test_seekg(std::iostream& str)
131 {
132 str.seekg(10);
133 }
134
test_seekp(std::iostream & str)135 void test_seekp(std::iostream& str)
136 {
137 str.seekp(10);
138 }
139
init_unit_test_suite(int,char * [])140 test_suite* init_unit_test_suite(int, char* [])
141 {
142 test_suite* test = BOOST_TEST_SUITE("stream state test");
143
144 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_read>::execute));
145 test->add(BOOST_TEST_CASE(&wrap_throw <&test_read>::execute));
146 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_read>::execute));
147
148 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_write>::execute));
149 test->add(BOOST_TEST_CASE(&wrap_throw <&test_write>::execute));
150 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_write>::execute));
151
152 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekg>::execute));
153 test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekg>::execute));
154 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekg>::execute));
155
156 test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekp>::execute));
157 test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekp>::execute));
158 test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekp>::execute));
159
160 return test;
161 }
162