1 | // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) |
2 | // (C) Copyright 2004-2007 Jonathan Turkanis |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
5 | |
6 | // See http://www.boost.org/libs/iostreams for documentation. |
7 | |
8 | #include <boost/iostreams/detail/config/wide_streams.hpp> |
9 | #ifdef BOOST_IOSTREAMS_NO_WIDE_STREAMS |
10 | # error wide streams not supported on this platform |
11 | #endif |
12 | |
13 | #include <algorithm> // equal. |
14 | #include <locale> |
15 | #include <string> |
16 | #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME. |
17 | #include <boost/iostreams/code_converter.hpp> |
18 | #include <boost/iostreams/copy.hpp> |
19 | #include <boost/iostreams/detail/add_facet.hpp> |
20 | #include <boost/iostreams/device/back_inserter.hpp> |
21 | #include <boost/iostreams/detail/config/windows_posix.hpp> |
22 | #include <boost/iostreams/device/file.hpp> |
23 | #if !defined(__COMO__) || !defined(BOOST_COMO_STRICT) |
24 | # if defined(BOOST_IOSTREAMS_NO_LIB) || defined(BOOST_ALL_NO_LIB) |
25 | # include "../src/file_descriptor.cpp" |
26 | # else |
27 | # include <boost/iostreams/device/file_descriptor.hpp> |
28 | # endif |
29 | #endif |
30 | #include <boost/iostreams/stream.hpp> |
31 | #include <boost/test/test_tools.hpp> |
32 | #include <boost/test/unit_test.hpp> |
33 | #include "detail/closable.hpp" |
34 | #include "detail/operation_sequence.hpp" |
35 | #include "detail/temp_file.hpp" |
36 | |
37 | // Include codevct facets |
38 | |
39 | #include "detail/null_padded_codecvt.hpp" |
40 | #include "detail/utf8_codecvt_facet.hpp" |
41 | #ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX |
42 | # include <codecvt/8859_1> |
43 | # include <codecvt/8859_10> |
44 | # include <codecvt/8859_13> |
45 | # include <codecvt/8859_14> |
46 | # include <codecvt/8859_15> |
47 | # include <codecvt/8859_16> |
48 | # include <codecvt/8859_2> |
49 | # include <codecvt/8859_3> |
50 | # include <codecvt/8859_4> |
51 | # include <codecvt/8859_5> |
52 | # include <codecvt/8859_6> |
53 | # include <codecvt/8859_7> |
54 | # include <codecvt/8859_8> |
55 | # include <codecvt/8859_9> |
56 | # include <codecvt/baltic> |
57 | # include <codecvt/big5> |
58 | # include <codecvt/cp037> |
59 | # include <codecvt/cp1006> |
60 | # include <codecvt/cp1026> |
61 | # include <codecvt/cp1250> |
62 | # include <codecvt/cp1251> |
63 | # include <codecvt/cp1252> |
64 | # include <codecvt/cp1253> |
65 | # include <codecvt/cp1254> |
66 | # include <codecvt/cp1255> |
67 | # include <codecvt/cp1256> |
68 | # include <codecvt/cp1257> |
69 | # include <codecvt/cp1258> |
70 | # include <codecvt/cp424> |
71 | # include <codecvt/cp437> |
72 | # include <codecvt/cp500> |
73 | # include <codecvt/cp737> |
74 | # include <codecvt/cp775> |
75 | # include <codecvt/cp850> |
76 | # include <codecvt/cp852> |
77 | # include <codecvt/cp855> |
78 | # include <codecvt/cp856> |
79 | # include <codecvt/cp857> |
80 | # include <codecvt/cp860> |
81 | # include <codecvt/cp861> |
82 | # include <codecvt/cp862> |
83 | # include <codecvt/cp863> |
84 | # include <codecvt/cp864> |
85 | # include <codecvt/cp865> |
86 | # include <codecvt/cp866> |
87 | # include <codecvt/cp869> |
88 | # include <codecvt/cp874> |
89 | # include <codecvt/cp875> |
90 | # include <codecvt/cp932> |
91 | # include <codecvt/cp936> |
92 | # include <codecvt/cp949> |
93 | # include <codecvt/cp950> |
94 | # include <codecvt/cyrillic> |
95 | # include <codecvt/ebcdic> |
96 | # include <codecvt/euc> |
97 | # include <codecvt/euc_0208> |
98 | # include <codecvt/gb12345> |
99 | # include <codecvt/gb2312> |
100 | # include <codecvt/greek> |
101 | # include <codecvt/iceland> |
102 | # include <codecvt/jis> |
103 | # include <codecvt/jis_0208> |
104 | # include <codecvt/jis0201> |
105 | # include <codecvt/ksc5601> |
106 | # include <codecvt/latin2> |
107 | # include <codecvt/one_one> |
108 | # include <codecvt/roman> |
109 | # include <codecvt/sjis> |
110 | # include <codecvt/sjis_0208> |
111 | # include <codecvt/turkish> |
112 | # include <codecvt/utf16> |
113 | # include <codecvt/utf8> |
114 | # include <codecvt/utf8_utf16> |
115 | # include <codecvt/xjis> |
116 | #endif // #ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX] |
117 | |
118 | #include <iostream> |
119 | |
120 | using namespace std; |
121 | using namespace boost::iostreams; |
122 | using namespace boost::iostreams::detail; |
123 | using namespace boost::iostreams::test; |
124 | using boost::unit_test::test_suite; |
125 | namespace io = boost::iostreams; |
126 | |
127 | const int max_length = 30; |
128 | const unsigned int pattern_length = 100; |
129 | const unsigned int pattern_reps = 100; |
130 | |
131 | template<typename Codecvt> |
132 | bool valid_char(typename codecvt_intern<Codecvt>::type c) |
133 | { |
134 | typedef typename codecvt_state<Codecvt>::type state_type; |
135 | typedef typename codecvt_intern<Codecvt>::type intern_type; |
136 | Codecvt cvt; |
137 | state_type state = state_type(); |
138 | const intern_type* nint; |
139 | char* next; |
140 | char buf[max_length]; |
141 | |
142 | return cvt.out( state, &c, &c + 1, nint, |
143 | buf, buf + max_length, next ) |
144 | == |
145 | codecvt_base::ok; |
146 | } |
147 | |
148 | template<typename Codecvt> |
149 | basic_string< |
150 | BOOST_DEDUCED_TYPENAME |
151 | codecvt_intern<Codecvt>::type |
152 | > |
153 | test_string() |
154 | { |
155 | typedef typename codecvt_intern<Codecvt>::type intern_type; |
156 | std::basic_string<intern_type> pattern, result; |
157 | for (intern_type c = 255; pattern.size() < pattern_length; --c) |
158 | if (valid_char<Codecvt>(c)) |
159 | pattern += c; |
160 | result.reserve(pattern.size() * pattern_reps); |
161 | for (unsigned int w = 0; w < pattern_reps; ++w) |
162 | result += pattern; |
163 | return result; |
164 | } |
165 | |
166 | // Como can't compile file_descriptor.cpp in strict mode; this failure |
167 | // is detected by file_descriptor_test.cpp. |
168 | #if !defined(__COMO__) || !defined(BOOST_COMO_STRICT) |
169 | typedef io::file_descriptor_source classic_file_source; |
170 | typedef io::file_descriptor_sink classic_file_sink; |
171 | #else |
172 | struct classic_file_source : io::source { |
173 | classic_file_source(const std::string& path) |
174 | : file_(new filebuf) |
175 | { |
176 | file_->pubimbue(locale::classic()); |
177 | file_->open(path.c_str(), BOOST_IOS::in | BOOST_IOS::binary); |
178 | } |
179 | streamsize read(char* s, streamsize n) { return file_->sgetn(s, n); } |
180 | boost::shared_ptr<filebuf> file_; |
181 | }; |
182 | |
183 | struct classic_file_sink : io::sink { |
184 | classic_file_sink(const std::string& path) |
185 | : file_(new filebuf) |
186 | { |
187 | file_->pubimbue(locale::classic()); |
188 | file_->open(path.c_str(), BOOST_IOS::out | BOOST_IOS::binary); |
189 | } |
190 | streamsize write(const char* s, streamsize n) { return file_->sputn(s, n); } |
191 | boost::shared_ptr<filebuf> file_; |
192 | }; |
193 | #endif |
194 | |
195 | template<typename Codecvt> |
196 | bool codecvt_test1() |
197 | { |
198 | typedef basic_string< |
199 | BOOST_DEDUCED_TYPENAME |
200 | codecvt_intern<Codecvt>::type |
201 | > string_type; |
202 | typedef code_converter<classic_file_source, Codecvt> wide_file_source; |
203 | typedef code_converter<classic_file_sink, Codecvt> wide_file_sink; |
204 | |
205 | BOOST_CHECK(Codecvt().max_length() <= max_length); |
206 | temp_file temp; |
207 | string_type test = test_string<Codecvt>(); |
208 | stream<wide_file_sink> out(temp.name()); |
209 | out.write(test.data(), static_cast<streamsize>(test.size())); |
210 | out.close(); |
211 | |
212 | stream<wide_file_source> in(temp.name()); |
213 | string_type test2; |
214 | io::copy(in, io::back_inserter(test2)); |
215 | |
216 | return test == test2; |
217 | } |
218 | |
219 | template<typename Codecvt> |
220 | bool codecvt_test2() |
221 | { |
222 | typedef basic_string< |
223 | BOOST_DEDUCED_TYPENAME |
224 | codecvt_intern<Codecvt>::type |
225 | > string_type; |
226 | typedef code_converter<classic_file_source> wide_file_source; |
227 | typedef code_converter<classic_file_sink> wide_file_sink; |
228 | |
229 | // Set global locale. |
230 | locale loc = add_facet(locale(), new Codecvt); |
231 | locale::global(loc: loc); |
232 | |
233 | temp_file temp; |
234 | string_type test = test_string<Codecvt>(); |
235 | stream<wide_file_sink> out(temp.name()); |
236 | out.write(s: test.data(), n: static_cast<streamsize>(test.size())); |
237 | out.close(); |
238 | |
239 | stream<wide_file_source> in(temp.name()); |
240 | string_type test2; |
241 | io::copy(in, io::back_inserter(test2)); |
242 | |
243 | return test == test2; |
244 | } |
245 | |
246 | template<typename Codecvt> |
247 | bool codecvt_test() |
248 | { |
249 | return codecvt_test1<Codecvt>() && codecvt_test2<Codecvt>(); |
250 | } |
251 | |
252 | void code_converter_test() |
253 | { |
254 | BOOST_CHECK((codecvt_test<utf8_codecvt_facet<wchar_t, char> >())); |
255 | BOOST_CHECK(codecvt_test<null_padded_codecvt>()); |
256 | BOOST_CHECK(codecvt_test<stateless_null_padded_codecvt>()); |
257 | #ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX |
258 | using namespace Dinkum::conversions; |
259 | BOOST_CHECK(codecvt_test< codecvt_8859_1<wchar_t> >()); |
260 | BOOST_CHECK(codecvt_test< codecvt_8859_10<wchar_t> >()); |
261 | BOOST_CHECK(codecvt_test< codecvt_8859_13<wchar_t> >()); |
262 | BOOST_CHECK(codecvt_test< codecvt_8859_14<wchar_t> >()); |
263 | BOOST_CHECK(codecvt_test< codecvt_8859_15<wchar_t> >()); |
264 | BOOST_CHECK(codecvt_test< codecvt_8859_16<wchar_t> >()); |
265 | BOOST_CHECK(codecvt_test< codecvt_8859_2<wchar_t> >()); |
266 | BOOST_CHECK(codecvt_test< codecvt_8859_3<wchar_t> >()); |
267 | BOOST_CHECK(codecvt_test< codecvt_8859_4<wchar_t> >()); |
268 | BOOST_CHECK(codecvt_test< codecvt_8859_5<wchar_t> >()); |
269 | BOOST_CHECK(codecvt_test< codecvt_8859_6<wchar_t> >()); |
270 | BOOST_CHECK(codecvt_test< codecvt_8859_7<wchar_t> >()); |
271 | BOOST_CHECK(codecvt_test< codecvt_8859_8<wchar_t> >()); |
272 | BOOST_CHECK(codecvt_test< codecvt_8859_9<wchar_t> >()); |
273 | BOOST_CHECK(codecvt_test< codecvt_baltic<wchar_t> >()); |
274 | BOOST_CHECK(codecvt_test< codecvt_big5<wchar_t> >()); |
275 | BOOST_CHECK(codecvt_test< codecvt_cp037<wchar_t> >()); |
276 | BOOST_CHECK(codecvt_test< codecvt_cp1006<wchar_t> >()); |
277 | BOOST_CHECK(codecvt_test< codecvt_cp1026<wchar_t> >()); |
278 | BOOST_CHECK(codecvt_test< codecvt_cp1250<wchar_t> >()); |
279 | BOOST_CHECK(codecvt_test< codecvt_cp1251<wchar_t> >()); |
280 | BOOST_CHECK(codecvt_test< codecvt_cp1252<wchar_t> >()); |
281 | BOOST_CHECK(codecvt_test< codecvt_cp1253<wchar_t> >()); |
282 | BOOST_CHECK(codecvt_test< codecvt_cp1254<wchar_t> >()); |
283 | BOOST_CHECK(codecvt_test< codecvt_cp1255<wchar_t> >()); |
284 | BOOST_CHECK(codecvt_test< codecvt_cp1256<wchar_t> >()); |
285 | BOOST_CHECK(codecvt_test< codecvt_cp1257<wchar_t> >()); |
286 | BOOST_CHECK(codecvt_test< codecvt_cp1258<wchar_t> >()); |
287 | BOOST_CHECK(codecvt_test< codecvt_cp424<wchar_t> >()); |
288 | BOOST_CHECK(codecvt_test< codecvt_cp437<wchar_t> >()); |
289 | BOOST_CHECK(codecvt_test< codecvt_cp500<wchar_t> >()); |
290 | BOOST_CHECK(codecvt_test< codecvt_cp737<wchar_t> >()); |
291 | BOOST_CHECK(codecvt_test< codecvt_cp775<wchar_t> >()); |
292 | BOOST_CHECK(codecvt_test< codecvt_cp850<wchar_t> >()); |
293 | BOOST_CHECK(codecvt_test< codecvt_cp852<wchar_t> >()); |
294 | BOOST_CHECK(codecvt_test< codecvt_cp855<wchar_t> >()); |
295 | BOOST_CHECK(codecvt_test< codecvt_cp856<wchar_t> >()); |
296 | BOOST_CHECK(codecvt_test< codecvt_cp857<wchar_t> >()); |
297 | BOOST_CHECK(codecvt_test< codecvt_cp860<wchar_t> >()); |
298 | BOOST_CHECK(codecvt_test< codecvt_cp861<wchar_t> >()); |
299 | BOOST_CHECK(codecvt_test< codecvt_cp862<wchar_t> >()); |
300 | BOOST_CHECK(codecvt_test< codecvt_cp863<wchar_t> >()); |
301 | BOOST_CHECK(codecvt_test< codecvt_cp864<wchar_t> >()); |
302 | BOOST_CHECK(codecvt_test< codecvt_cp865<wchar_t> >()); |
303 | BOOST_CHECK(codecvt_test< codecvt_cp866<wchar_t> >()); |
304 | BOOST_CHECK(codecvt_test< codecvt_cp869<wchar_t> >()); |
305 | BOOST_CHECK(codecvt_test< codecvt_cp874<wchar_t> >()); |
306 | BOOST_CHECK(codecvt_test< codecvt_cp875<wchar_t> >()); |
307 | BOOST_CHECK(codecvt_test< codecvt_cp932<wchar_t> >()); |
308 | BOOST_CHECK(codecvt_test< codecvt_cp936<wchar_t> >()); |
309 | BOOST_CHECK(codecvt_test< codecvt_cp949<wchar_t> >()); |
310 | BOOST_CHECK(codecvt_test< codecvt_cp950<wchar_t> >()); |
311 | BOOST_CHECK(codecvt_test< codecvt_cyrillic<wchar_t> >()); |
312 | BOOST_CHECK(codecvt_test< codecvt_ebcdic<wchar_t> >()); |
313 | BOOST_CHECK(codecvt_test< codecvt_euc<wchar_t> >()); |
314 | BOOST_CHECK(codecvt_test< codecvt_euc_0208<wchar_t> >()); |
315 | BOOST_CHECK(codecvt_test< codecvt_gb12345<wchar_t> >()); |
316 | BOOST_CHECK(codecvt_test< codecvt_gb2312<wchar_t> >()); |
317 | BOOST_CHECK(codecvt_test< codecvt_greek<wchar_t> >()); |
318 | BOOST_CHECK(codecvt_test< codecvt_iceland<wchar_t> >()); |
319 | BOOST_CHECK(codecvt_test< codecvt_jis<wchar_t> >()); |
320 | BOOST_CHECK(codecvt_test< codecvt_jis_0208<wchar_t> >()); |
321 | BOOST_CHECK(codecvt_test< codecvt_jis0201<wchar_t> >()); |
322 | BOOST_CHECK(codecvt_test< codecvt_ksc5601<wchar_t> >()); |
323 | BOOST_CHECK(codecvt_test< codecvt_latin2<wchar_t> >()); |
324 | BOOST_CHECK(codecvt_test< codecvt_one_one<wchar_t> >()); |
325 | BOOST_CHECK(codecvt_test< codecvt_roman<wchar_t> >()); |
326 | BOOST_CHECK(codecvt_test< codecvt_sjis<wchar_t> >()); |
327 | BOOST_CHECK(codecvt_test< codecvt_sjis_0208<wchar_t> >()); |
328 | BOOST_CHECK(codecvt_test< codecvt_turkish<wchar_t> >()); |
329 | BOOST_CHECK(codecvt_test< codecvt_utf16<wchar_t> >()); |
330 | BOOST_CHECK(codecvt_test< codecvt_utf8<wchar_t> >()); |
331 | BOOST_CHECK(codecvt_test< codecvt_utf8_utf16<wchar_t> >()); |
332 | #endif |
333 | } |
334 | |
335 | /* Defer pending further testing |
336 | void close_test() |
337 | { |
338 | typedef utf8_codecvt_facet<wchar_t, char> codecvt_type; |
339 | |
340 | // Test code converter based on a source |
341 | { |
342 | operation_sequence seq; |
343 | io::wchain<input> ch; |
344 | ch.push( |
345 | code_converter<closable_device<input>, codecvt_type>( |
346 | seq.new_operation(1) |
347 | ) |
348 | ); |
349 | BOOST_CHECK_NO_THROW(ch.reset()); |
350 | BOOST_CHECK_OPERATION_SEQUENCE(seq); |
351 | } |
352 | |
353 | // Test code converter based on a sink |
354 | { |
355 | operation_sequence seq; |
356 | io::wchain<output> ch; |
357 | ch.push( |
358 | code_converter<closable_device<output>, codecvt_type>( |
359 | seq.new_operation(1) |
360 | ) |
361 | ); |
362 | BOOST_CHECK_NO_THROW(ch.reset()); |
363 | BOOST_CHECK_OPERATION_SEQUENCE(seq); |
364 | } |
365 | |
366 | // Test code converter based on a bidirectional device |
367 | { |
368 | operation_sequence seq; |
369 | io::wchain<bidirectional> ch; |
370 | ch.push( |
371 | code_converter<closable_device<bidirectional>, codecvt_type>( |
372 | seq.new_operation(1), |
373 | seq.new_operation(2) |
374 | ) |
375 | ); |
376 | BOOST_CHECK_NO_THROW(ch.reset()); |
377 | BOOST_CHECK_OPERATION_SEQUENCE(seq); |
378 | } |
379 | }*/ |
380 | |
381 | test_suite* init_unit_test_suite(int, char* []) |
382 | { |
383 | test_suite* test = BOOST_TEST_SUITE("code_converter test" ); |
384 | test->add(BOOST_TEST_CASE(&code_converter_test)); |
385 | //test->add(BOOST_TEST_CASE(&close_test)); |
386 | return test; |
387 | } |
388 | |