stream_state_test.cpp 5.7 KB

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