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