1 // -----------------------------------------------------------
2 // Copyright (c) 2001 Jeremy Siek
3 // Copyright (c) 2003-2006 Gennaro Prota
4 //
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // -----------------------------------------------------------
10
11 #include <fstream>
12 #include <string>
13 #include <cstddef> // for std::size_t
14 #include <stdexcept> // for std::logic_error
15 #include <assert.h>
16
17 #include <boost/config.hpp>
18 #if !defined (BOOST_NO_STRINGSTREAM)
19 # include <sstream>
20 #endif
21
22 #include "bitset_test.hpp"
23 #include <boost/dynamic_bitset/dynamic_bitset.hpp>
24 #include <boost/config/workaround.hpp>
25
26
27 // Codewarrior 8.3 for Win fails without this.
28 // Thanks Howard Hinnant ;)
29 #if defined __MWERKS__ && BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x
30 # pragma parse_func_templ off
31 #endif
32
33
34 #if defined BOOST_NO_STD_WSTRING || defined BOOST_NO_STD_LOCALE
35 # define BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS
36 #endif
37
38 #if !defined BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS
widen_string(const std::string & str,const std::locale & loc=std::locale ())39 std::wstring widen_string( const std::string & str,
40 const std::locale & loc = std::locale() )
41 {
42 std::wstring result;
43 const std::string::size_type len = str.length();
44 if(len != 0) {
45
46 typedef std::ctype<wchar_t> ct_type;
47 typedef std::wstring::traits_type tr_type;
48 const ct_type & ct = BOOST_USE_FACET(ct_type, loc);
49
50 result.resize(len);
51 for (std::size_t i = 0; i < len; ++i)
52 tr_type::assign(result[i], ct.widen(str[i]));
53
54 }
55 return result;
56 }
57 #endif
58
59 template <typename Block>
run_test_cases(BOOST_EXPLICIT_TEMPLATE_TYPE (Block))60 void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) )
61 {
62
63 typedef boost::dynamic_bitset<Block> bitset_type;
64 typedef bitset_test<bitset_type> Tests;
65
66 //=====================================================================
67 // Test stream operator<<
68 {
69
70 // The test "variables" are: the stream type and its state, the
71 // exception mask, the width, the fill char and the padding side (left/right)
72
73 std::ios::iostate masks[] = {
74 std::ios::goodbit,
75 std::ios::eofbit,
76 std::ios::failbit,
77 std::ios::eofbit | std::ios::failbit
78 };
79
80 static std::string strings[] = {
81 std::string(""),
82 std::string("0"),
83 std::string("1"),
84 std::string("11100"),
85 get_long_string()
86 };
87
88 char fill_chars[] = { '*', 'x', ' ' };
89
90 std::size_t num_masks = sizeof(masks) / sizeof(masks[0]);
91 std::size_t num_strings = sizeof(strings) / sizeof(strings[0]);
92 std::size_t num_chars = sizeof(fill_chars) / sizeof(fill_chars[0]);
93
94 std::fstream not_good_stream("dynamic_bitset_tests - this file shouldn't exist",
95 std::ios::in);
96
97
98 for (std::size_t mi = 0; mi < num_masks; ++mi) {
99 for (std::size_t si = 0; si < num_strings; ++si) {
100
101 std::streamsize slen = (std::streamsize)(strings[si].length());
102
103 assert( (std::numeric_limits<std::streamsize>::max)()
104 >=(std::streamsize)(1+slen*2) );
105
106 for (std::size_t ci = 0; ci < num_chars; ++ci) {
107
108 // note how "negative widths" are tested too
109 const std::streamsize widths[] = { -1 - slen/2, 0, slen/2, 1 + slen*2 };
110 std::size_t num_widths = sizeof(widths) / sizeof(widths[0]);
111
112 for (std::size_t wi = 0; wi < num_widths; ++wi) {
113 std::streamsize w = widths[wi];
114 {
115 // test 0 - stream !good()
116 if(not_good_stream.good())
117 throw std::logic_error("Error in operator << tests"
118 " - please, double check");
119 bitset_type b(strings[si]);
120 not_good_stream.width(w);
121 not_good_stream.fill(fill_chars[ci]);
122 try { not_good_stream.exceptions(masks[mi]); } catch(...) {}
123
124 Tests::stream_inserter(b, not_good_stream, "<unused_string>");
125 }
126 {
127 // test 1a - file stream
128 scoped_temp_file stf;
129 bitset_type b(strings[si]);
130 std::ofstream file(stf.path().string().c_str(), std::ios::trunc);
131 file.width(w);
132 file.fill(fill_chars[ci]);
133 file.exceptions(masks[mi]);
134 Tests::stream_inserter(b, file, stf.path().string().c_str());
135 }
136 {
137 //NOTE: there are NO string stream tests
138 }
139 #if !defined (BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS)
140 {
141 // test 1b - wide file stream
142 scoped_temp_file stf;
143 bitset_type b(strings[si]);
144 std::wofstream file(stf.path().string().c_str());
145 file.width(w);
146 file.fill(fill_chars[ci]);
147 file.exceptions(masks[mi]);
148 Tests::stream_inserter(b, file, stf.path().string().c_str());
149 }
150 #endif
151 }
152 }
153 }
154 } // for (; mi..)
155
156 }
157
158 //=====================================================================
159 // Test stream operator>>
160 {
161
162 // The test "variables" are: the stream type, the exception mask,
163 // the actual contents (and/or state) of the stream, and width.
164 //
165 // With few exceptions, each test case consists of writing a different
166 // assortment of digits and "whitespaces" to a text stream and then checking
167 // that what was written gets read back unchanged. That's NOT guaranteed by
168 // the standard, unless the assortment always ends with a '\n' and satisfies
169 // other conditions (see C99, 7.19.2/2), however it works in practice and is
170 // a good "real life" test. Some characters, such as '\v' and '\f', are not
171 // used exactly because they are the ones which will most likely give problems
172 // on some systems (for instance '\f' could actually be written as a sequence
173 // of new-lines, and we could never be able to read it back)
174 //
175 // Note how the bitset object is not initially empty. That helps checking
176 // that it isn't erroneously clear()ed by operator>>.
177
178
179 std::ios::iostate masks[] = {
180 std::ios::goodbit,
181 std::ios::eofbit,
182 std::ios::failbit,
183 std::ios::eofbit | std::ios::failbit
184 };
185
186 const std::string spaces = "\t\n "; //"\t\n\v\f ";
187
188 const std::string long_string = get_long_string();
189 /*const*/ static std::string strings[] = {
190 // NOTE: "const" gives the usual problems with Borland
191 // (in Tests::stream_extractor instantiation)
192
193
194 #if !(defined BOOST_BORLANDC \
195 && BOOST_WORKAROUND(BOOST_RWSTD_VER, BOOST_TESTED_AT(0x20101)))
196 // Borland 5.5.1 with RW library crashes
197 // empty string
198 std::string(""),
199 // no bitset
200 spaces,
201 #endif
202 // no bitset
203 std::string("x"),
204 std::string("\t xyz"),
205
206 // bitset of size 1
207 std::string("0"),
208 std::string("1"),
209
210 std::string(" 0 "),
211 std::string(" 1 "),
212 spaces + "1",
213 "1" + spaces,
214 spaces + "1" + spaces,
215 std::string(" x1x "),
216 std::string(" 1x "),
217
218 // long bitset
219 long_string,
220 " " + long_string + " xyz",
221 spaces + long_string,
222 spaces + long_string + spaces
223 };
224
225
226 //-----------------------------------------------------
227
228 std::stringstream not_good_stream;
229 not_good_stream << "test";
230 std::string sink;
231 not_good_stream >> sink; // now the stream should be in eof state
232
233 const std::size_t num_masks = sizeof(masks) / sizeof(masks[0]);
234 const std::size_t num_strings = sizeof(strings) / sizeof(strings[0]);
235
236 for (std::size_t mi = 0; mi < num_masks; ++mi) {
237 for (std::size_t si = 0; si < num_strings; ++si) {
238
239 const std::streamsize slen = (std::streamsize)(strings[si].length());
240 assert((std::numeric_limits<std::streamsize>::max)() >= (std::streamsize)(1+slen*2));
241
242 std::streamsize widths[] = { -1, 0, slen/2, slen, 1 + slen*2 };
243 std::size_t num_widths = sizeof(widths) / sizeof(widths[0]);
244
245 for(std::size_t wi = 0; wi < num_widths; ++wi) {
246 const std::streamsize w = widths[wi];
247
248 // test 0 - !good() stream
249 {
250 if(not_good_stream.good())
251 throw std::logic_error("Error in operator >> tests"
252 " - please, double check");
253 bitset_type b(1, 15ul); // note: b is not empty
254 not_good_stream.width(w);
255 try { not_good_stream.exceptions(masks[mi]); } catch(...) {}
256 std::string irrelevant;
257 Tests::stream_extractor(b, not_good_stream, irrelevant);
258 }
259 // test 1a - (narrow) file stream
260 {
261 scoped_temp_file stf;
262 bitset_type b(1, 255ul);
263 {
264 std::ofstream f(stf.path().string().c_str());
265 f << strings[si];
266 }
267
268 std::ifstream f(stf.path().string().c_str());
269 f.width(w);
270 f.exceptions(masks[mi]);
271 Tests::stream_extractor(b, f, strings[si]);
272 }
273 #if !defined(BOOST_NO_STRINGSTREAM)
274 // test 2a - stringstream
275 {
276 bitset_type b(1, 255ul);
277 std::istringstream stream(strings[si]);
278 stream.width(w);
279 stream.exceptions(masks[mi]);
280 Tests::stream_extractor(b, stream, strings[si]);
281 }
282 #endif
283
284 #if !defined(BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS)
285 // test 1b - wchar_t file stream
286 {
287 scoped_temp_file stf;
288 std::wstring wstr = widen_string(strings[si]);
289 bitset_type b(1, 255ul);
290 {
291 std::basic_ofstream<wchar_t> of(stf.path().string().c_str());
292 of << wstr;
293 }
294
295 std::basic_ifstream<wchar_t> f(stf.path().string().c_str());
296 f.width(w);
297 f.exceptions(masks[mi]);
298 Tests::stream_extractor(b, f, wstr);
299 }
300 // test 2b - wstringstream
301 {
302 bitset_type b(1, 255ul);
303 std::wstring wstr = widen_string(strings[si]);
304
305 std::wistringstream wstream(wstr);
306 wstream.width(w);
307 wstream.exceptions(masks[mi]);
308 Tests::stream_extractor(b, wstream, wstr);
309 }
310 #endif // BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS
311
312 }
313 }
314
315 } // for ( mi = 0; ...)
316
317
318 }
319 //=====================================================================
320 // << Any other tests go here >>
321 // .....
322
323 }
324
325
326 int
main()327 main()
328 {
329 run_test_cases<unsigned char>();
330 run_test_cases<unsigned short>();
331 run_test_cases<unsigned int>();
332 run_test_cases<unsigned long>();
333 # ifdef BOOST_HAS_LONG_LONG
334 run_test_cases< ::boost::ulong_long_type>();
335 # endif
336
337 return boost::report_errors();
338 }
339