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>
valid_char(typename codecvt_intern<Codecvt>::type c)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 >
test_string()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 {
classic_file_sourceclassic_file_source173         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         }
readclassic_file_source179         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  {
classic_file_sinkclassic_file_sink184         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         }
writeclassic_file_sink190         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>
codecvt_test1()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>
codecvt_test2()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);
232 
233     temp_file                 temp;
234     string_type               test = test_string<Codecvt>();
235     stream<wide_file_sink>    out(temp.name());
236     out.write(test.data(), 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>
codecvt_test()247 bool codecvt_test()
248 {
249     return codecvt_test1<Codecvt>() && codecvt_test2<Codecvt>();
250 }
251 
code_converter_test()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 
init_unit_test_suite(int,char * [])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