1 //  Boost ios_state_test.cpp test file  --------------------------------------//
2 
3 //  Copyright 2002, 2003 Daryle Walker.  Use, modification, and distribution are
4 //  subject to the Boost Software License, Version 1.0.  (See accompanying file
5 //  LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
6 
7 //  See <http://www.boost.org/libs/io/> for the library's home page.
8 
9 //  Revision History
10 //   15 Jun 2003  Adjust to changes in Boost.Test (Daryle Walker)
11 //   26 Feb 2002  Initial version (Daryle Walker)
12 
13 #include <boost/test/minimal.hpp>  // main, BOOST_CHECK, etc.
14 
15 #include <boost/cstdlib.hpp>       // for boost::exit_success
16 #include <boost/io/ios_state.hpp>  // for boost::io::ios_flags_saver, etc.
17 
18 #include <cstddef>    // for std::size_t
19 #include <iomanip>    // for std::setw
20 #include <ios>        // for std::ios_base, std::streamsize, etc.
21 #include <iostream>   // for std::cout, etc.
22 #include <istream>    // for std::istream
23 #include <locale>     // for std::numpunct, std::locale
24 #include <ostream>    // for std::endl, std::ostream
25 #include <streambuf>  // for std::streambuf
26 #include <string>     // for std::string
27 
28 
29 // Facet with the bool names spelled backwards
30 class backward_bool_names
31     : public std::numpunct<char>
32 {
33     typedef std::numpunct<char>  base_type;
34 
35 public:
backward_bool_names(std::size_t refs=0)36     explicit  backward_bool_names( std::size_t refs = 0 )
37         : base_type( refs )
38         {}
39 
40 protected:
~backward_bool_names()41     virtual ~backward_bool_names() {}
42 
do_truename() const43     virtual  base_type::string_type  do_truename() const
44         { return "eurt"; }
do_falsename() const45     virtual  base_type::string_type  do_falsename() const
46         { return "eslaf"; }
47 };
48 
49 
50 // Index to test custom storage
51 int const  my_index = std::ios_base::xalloc();
52 
53 // Test data
54 char const    test_string[] = "Hello world";
55 int const     test_num1 = -16;
56 double const  test_num2 = 34.5678901234;
57 bool const    test_bool = true;
58 
59 
60 // Function prototypes
61 void  saver_tests_1( std::istream &input, std::ostream &output,
62  std::ostream &err );
63 void  saver_tests_2( std::istream &input, std::ostream &output,
64  std::ostream &err );
65 
66 
67 // Test program
68 int
test_main(int,char * [])69 test_main
70 (
71     int         ,   // "argc" is unused
72     char *      []  // "argv" is unused
73 )
74 {
75     using std::cout;
76     using std::ios_base;
77     using std::streamsize;
78     using std::cin;
79 
80     cout << "The original data is:\n";
81     cout << '\t' << test_string << '\n';
82     cout << '\t' << test_num1 << '\n';
83     cout << '\t' << test_num2 << '\n';
84     cout << '\t' << std::boolalpha << test_bool << std::endl;
85 
86     // Save states for comparison later
87     ios_base::fmtflags const  cout_flags = cout.flags();
88     streamsize const          cout_precision = cout.precision();
89     streamsize const          cout_width = cout.width();
90     ios_base::iostate const   cout_iostate = cout.rdstate();
91     ios_base::iostate const   cout_exceptions = cout.exceptions();
92     std::ostream * const      cin_tie = cin.tie();
93     std::streambuf * const    cout_sb = cout.rdbuf();
94     char const                cout_fill = cout.fill();
95     std::locale const         cout_locale = cout.getloc();
96 
97     cout.iword( my_index ) = 42L;
98     cout.pword( my_index ) = &cin;
99 
100     // Run saver tests with changing separate from saving
101     saver_tests_1( cin, cout, std::cerr );
102 
103     // Check if states are back to normal
104     BOOST_CHECK( &cin == cout.pword(my_index) );
105     BOOST_CHECK( 42L == cout.iword(my_index) );
106     BOOST_CHECK( cout_locale == cout.getloc() );
107     BOOST_CHECK( cout_fill == cout.fill() );
108     BOOST_CHECK( cout_sb == cout.rdbuf() );
109     BOOST_CHECK( cin_tie == cin.tie() );
110     BOOST_CHECK( cout_exceptions == cout.exceptions() );
111     BOOST_CHECK( cout_iostate == cout.rdstate() );
112     BOOST_CHECK( cout_width == cout.width() );
113     BOOST_CHECK( cout_precision == cout.precision() );
114     BOOST_CHECK( cout_flags == cout.flags() );
115 
116     // Run saver tests with combined saving and changing
117     saver_tests_2( cin, cout, std::cerr );
118 
119     // Check if states are back to normal
120     BOOST_CHECK( &cin == cout.pword(my_index) );
121     BOOST_CHECK( 42L == cout.iword(my_index) );
122     BOOST_CHECK( cout_locale == cout.getloc() );
123     BOOST_CHECK( cout_fill == cout.fill() );
124     BOOST_CHECK( cout_sb == cout.rdbuf() );
125     BOOST_CHECK( cin_tie == cin.tie() );
126     BOOST_CHECK( cout_exceptions == cout.exceptions() );
127     BOOST_CHECK( cout_iostate == cout.rdstate() );
128     BOOST_CHECK( cout_width == cout.width() );
129     BOOST_CHECK( cout_precision == cout.precision() );
130     BOOST_CHECK( cout_flags == cout.flags() );
131 
132     return boost::exit_success;
133 }
134 
135 // Save, change, and restore stream properties
136 void
saver_tests_1(std::istream & input,std::ostream & output,std::ostream & err)137 saver_tests_1
138 (
139     std::istream &  input,
140     std::ostream &  output,
141     std::ostream &  err
142 )
143 {
144     using std::locale;
145     using std::ios_base;
146     using std::setw;
147 
148     boost::io::ios_flags_saver const      ifls( output );
149     boost::io::ios_precision_saver const  iprs( output );
150     boost::io::ios_width_saver const      iws( output );
151     boost::io::ios_tie_saver const        its( input );
152     boost::io::ios_rdbuf_saver const      irs( output );
153     boost::io::ios_fill_saver const       ifis( output );
154     boost::io::ios_locale_saver const     ils( output );
155     boost::io::ios_iword_saver const      iis( output, my_index );
156     boost::io::ios_pword_saver const      ipws( output, my_index );
157 
158     locale  loc( locale::classic(), new backward_bool_names );
159 
160     input.tie( &err );
161     output.rdbuf( err.rdbuf() );
162     output.iword( my_index ) = 69L;
163     output.pword( my_index ) = &err;
164 
165     output << "The data is (again):\n";
166     output.setf( ios_base::showpos | ios_base::boolalpha );
167     output.setf( ios_base::internal, ios_base::adjustfield );
168     output.fill( '@' );
169     output.precision( 9 );
170     output << '\t' << test_string << '\n';
171     output << '\t' << setw( 10 ) << test_num1 << '\n';
172     output << '\t' << setw( 15 ) << test_num2 << '\n';
173     output.imbue( loc );
174     output << '\t' << test_bool << '\n';
175 
176     BOOST_CHECK( &err == output.pword(my_index) );
177     BOOST_CHECK( 69L == output.iword(my_index) );
178 
179     try
180     {
181         boost::io::ios_exception_saver const  ies( output );
182         boost::io::ios_iostate_saver const    iis( output );
183 
184         output.exceptions( ios_base::eofbit );
185         output.setstate( ios_base::eofbit );
186         BOOST_ERROR( "previous line should have thrown" );
187     }
188     catch ( ios_base::failure &f )
189     {
190         err << "Got the expected I/O failure: \"" << f.what() << "\".\n";
191         BOOST_CHECK( output.exceptions() == ios_base::goodbit );
192     }
193     catch ( ... )
194     {
195         err << "Got an unknown error when doing exception test!\n";
196         throw;
197     }
198 }
199 
200 // Save & change and restore stream properties
201 void
saver_tests_2(std::istream & input,std::ostream & output,std::ostream & err)202 saver_tests_2
203 (
204     std::istream &  input,
205     std::ostream &  output,
206     std::ostream &  err
207 )
208 {
209     using std::locale;
210     using std::ios_base;
211 
212     boost::io::ios_tie_saver const    its( input, &err );
213     boost::io::ios_rdbuf_saver const  irs( output, err.rdbuf() );
214     boost::io::ios_iword_saver const  iis( output, my_index, 69L );
215     boost::io::ios_pword_saver const  ipws( output, my_index, &err );
216     output << "The data is (a third time; adding the numbers):\n";
217 
218     boost::io::ios_flags_saver const      ifls( output, (output.flags()
219      & ~ios_base::adjustfield) | ios_base::showpos | ios_base::boolalpha
220      | (ios_base::internal & ios_base::adjustfield) );
221     boost::io::ios_precision_saver const  iprs( output, 9 );
222     boost::io::ios_fill_saver const       ifis( output, '@' );
223     output << '\t' << test_string << '\n';
224 
225     boost::io::ios_width_saver const  iws( output, 12 );
226     output.put( '\t' );
227     output << test_num1 + test_num2;
228     output.put( '\n' );
229 
230     locale                             loc( locale::classic(),
231      new backward_bool_names );
232     boost::io::ios_locale_saver const  ils( output, loc );
233     output << '\t' << test_bool << '\n';
234 
235     BOOST_CHECK( &err == output.pword(my_index) );
236     BOOST_CHECK( 69L == output.iword(my_index) );
237 
238     try
239     {
240         boost::io::ios_exception_saver const  ies( output, ios_base::eofbit  );
241         boost::io::ios_iostate_saver const    iis( output, output.rdstate()
242          | ios_base::eofbit );
243 
244         BOOST_ERROR( "previous line should have thrown" );
245     }
246     catch ( ios_base::failure &f )
247     {
248         err << "Got the expected I/O failure: \"" << f.what() << "\".\n";
249         BOOST_CHECK( output.exceptions() == ios_base::goodbit );
250     }
251     catch ( ... )
252     {
253         err << "Got an unknown error when doing exception test!\n";
254         throw;
255     }
256 }
257