Imported Upstream version 1.49.0
[platform/upstream/boost.git] / libs / iostreams / test / restrict_test.cpp
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2005-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 // Allow this file to be used by slice_test.hpp. It is important not to 
9 // replace BOOST_RESTRICT with BOOST_IOSTREAMS_RESTRICT here, since that
10 // would interfere with the oepration of the header 
11 // <boost/iostreams/restrict.hpp>
12 #include <iostream>
13
14 #if defined(BOOST_RESTRICT_USE_SLICE)
15 #  include <boost/iostreams/slice.hpp>
16 #  define BOOST_RESTRICT slice
17 #else
18 #  include <boost/iostreams/restrict.hpp>
19 #  define BOOST_RESTRICT restrict
20 #endif
21
22 #include <algorithm>         // equal.
23 #include <cctype>
24 #include <iterator>          // back_inserter.
25 #include <vector>
26 #include <boost/iostreams/copy.hpp>
27 #include <boost/iostreams/device/file.hpp>
28 #include <boost/iostreams/device/null.hpp>
29 #include <boost/iostreams/filtering_stream.hpp>
30 #include <boost/test/test_tools.hpp>
31 #include <boost/test/unit_test.hpp>
32 #include "detail/closable.hpp"
33 #include "detail/constants.hpp"
34 #include "detail/filters.hpp"
35 #include "detail/operation_sequence.hpp"
36 #include "detail/sequence.hpp"
37 #include "detail/temp_file.hpp"
38 #include "detail/verification.hpp"
39
40 using namespace std;
41 using namespace boost::iostreams;
42 using namespace boost::iostreams::test;
43 using boost::unit_test::test_suite;
44 namespace io = boost::iostreams;
45
46 const char pad_char = '\n';
47 const int small_padding = 50;
48 const int large_padding = default_device_buffer_size + 50;
49
50 void write_padding(std::ofstream& out, int len)
51 {
52     for (int z = 0; z < len; ++z)
53         out.put(pad_char);
54 }
55
56 struct restricted_test_file : public temp_file {
57     restricted_test_file(int padding, bool half_open = false)
58         {
59             BOOST_IOS::openmode mode = 
60                 BOOST_IOS::out | BOOST_IOS::binary;
61             ::std::ofstream f(name().c_str(), mode);
62             write_padding(f, padding);
63             const char* buf = narrow_data();
64             for (int z = 0; z < data_reps; ++z)
65                 f.write(buf, data_length());
66             if (!half_open)
67                 write_padding(f, padding);
68         }
69 };
70
71 struct restricted_test_sequence : public std::vector<char> {
72     restricted_test_sequence(int padding, bool half_open = false)
73         {
74             for (int z = 0; z < padding; ++z)
75                 push_back(pad_char);
76             const char* buf = narrow_data();
77             for (int w = 0; w < data_reps; ++w)
78                 insert(end(), buf, buf + data_length());
79             if (!half_open)
80                 for (int x = 0; x < padding; ++x)
81                     push_back(pad_char);
82         }
83 };
84
85 struct restricted_uppercase_file : public temp_file {
86     restricted_uppercase_file(int padding, bool half_open = false)
87         {
88             BOOST_IOS::openmode mode = 
89                 BOOST_IOS::out | BOOST_IOS::binary;
90             ::std::ofstream f(name().c_str(), mode);
91             write_padding(f, padding);
92             const char* buf = narrow_data();
93             for (int z = 0; z < data_reps; ++z)
94                 for (int w = 0; w < data_length(); ++w)
95                     f.put((char) std::toupper(buf[w]));
96             if (!half_open)
97                 write_padding(f, padding);
98         }
99 };
100
101 struct restricted_lowercase_file : public temp_file {
102     restricted_lowercase_file(int padding, bool half_open = false)
103         {
104             BOOST_IOS::openmode mode = 
105                 BOOST_IOS::out | BOOST_IOS::binary;
106             ::std::ofstream f(name().c_str(), mode);
107             write_padding(f, padding);
108             const char* buf = narrow_data();
109             for (int z = 0; z < data_reps; ++z)
110                 for (int w = 0; w < data_length(); ++w)
111                     f.put((char) std::tolower(buf[w]));
112             if (!half_open)
113                 write_padding(f, padding);
114         }
115 };
116
117 // Can't have a restricted view of a non-seekble output filter.
118 struct tolower_seekable_filter : public seekable_filter {
119     typedef char char_type;
120     struct category 
121         : output_seekable,
122           filter_tag
123         { };
124     template<typename Sink>
125     bool put(Sink& s, char c)
126     { return boost::iostreams::put(s, (char) std::tolower(c)); }
127
128     template<typename Sink>
129     std::streampos seek(Sink& s, stream_offset off, BOOST_IOS::seekdir way)
130     { return boost::iostreams::seek(s, off, way); }
131 };
132
133 void read_device()
134 {
135     {
136         restricted_test_file   src1(small_padding);
137         test_file              src2;
138         stream_offset          off = small_padding,
139                                len = data_reps * data_length();
140         filtering_istream      first( 
141             BOOST_RESTRICT(file_source(src1.name(), in_mode), off, len));
142         ifstream               second(src2.name().c_str(), in_mode);
143         BOOST_CHECK_MESSAGE(
144             compare_streams_in_chunks(first, second),
145             "failed reading from restriction<Device> with small padding"
146         );
147     }
148
149     {
150         restricted_test_file   src1(large_padding);
151         test_file              src2;
152         stream_offset          off = large_padding,
153                                len = data_reps * data_length();
154         filtering_istream      first(
155             BOOST_RESTRICT(file_source(src1.name(), in_mode), off, len));
156         ifstream               second(src2.name().c_str(), in_mode);
157         BOOST_CHECK_MESSAGE(
158             compare_streams_in_chunks(first, second),
159             "failed reading from restriction<Device> with large padding"
160         );
161     }
162
163     {
164         restricted_test_file   src1(small_padding, true);
165         test_file              src2;
166         stream_offset          off = small_padding;
167         filtering_istream      first(
168             BOOST_RESTRICT(file_source(src1.name(), in_mode), off));
169         ifstream               second(src2.name().c_str(), in_mode);
170         BOOST_CHECK_MESSAGE(
171             compare_streams_in_chunks(first, second),
172             "failed reading from half-open restriction<Device> "
173             "with small padding"
174         );
175     }
176
177     {
178         restricted_test_file   src1(large_padding, true);
179         test_file              src2;
180         stream_offset          off = large_padding;
181         filtering_istream      first(
182             BOOST_RESTRICT(file_source(src1.name(), in_mode), off));
183         ifstream               second(src2.name().c_str(), in_mode);
184         BOOST_CHECK_MESSAGE(
185             compare_streams_in_chunks(first, second),
186             "failed reading from half-open restriction<Device> "
187             "with large padding"
188         );
189     }
190 }
191
192 void read_direct_device()
193 {
194     {
195         test_sequence<char>       first;
196         restricted_test_sequence  src(small_padding);
197         array_source              array_src(&src[0], &src[0] + src.size());
198         stream_offset             off = small_padding,
199                                   len = data_reps * data_length();
200         filtering_istream         second(BOOST_RESTRICT(array_src, off, len));
201         BOOST_CHECK_MESSAGE(
202             compare_container_and_stream(first, second),
203             "failed reading from restriction<Direct>"
204         );
205     }
206
207     {
208         test_sequence<char>       first;
209         restricted_test_sequence  src(small_padding, true);
210         array_source              array_src(&src[0], &src[0] + src.size());
211         stream_offset             off = small_padding;
212         filtering_istream         second(BOOST_RESTRICT(array_src, off));
213         BOOST_CHECK_MESSAGE(
214             compare_container_and_stream(first, second),
215             "failed reading from half-open restriction<Direct>"
216         );
217     }
218 }
219
220 void read_filter()
221 {
222     {
223         restricted_test_file   src1(small_padding);
224         uppercase_file         src2;
225         stream_offset          off = small_padding,
226                                len = data_reps * data_length();
227         filtering_istream      first;
228         first.push(BOOST_RESTRICT(toupper_filter(), off, len));
229         first.push(file_source(src1.name(), in_mode));
230         ifstream           second(src2.name().c_str(), in_mode);
231         BOOST_CHECK_MESSAGE(
232             compare_streams_in_chunks(first, second),
233             "failed reading from restriction<Filter> with small padding"
234         );
235     }
236
237     {
238         restricted_test_file   src1(large_padding);
239         uppercase_file         src2;
240         stream_offset          off = large_padding,
241                                len = data_reps * data_length();
242         filtering_istream      first;
243         first.push(BOOST_RESTRICT(toupper_filter(), off, len));
244         first.push(file_source(src1.name(), in_mode));
245         ifstream           second(src2.name().c_str(), in_mode);
246         BOOST_CHECK_MESSAGE(
247             compare_streams_in_chunks(first, second),
248             "failed reading from restriction<Filter> with large padding"
249         );
250     }
251
252     {
253         restricted_test_file   src1(small_padding, true);
254         uppercase_file         src2;
255         stream_offset          off = small_padding;
256         filtering_istream      first;
257         first.push(BOOST_RESTRICT(toupper_filter(), off));
258         first.push(file_source(src1.name(), in_mode));
259         ifstream           second(src2.name().c_str(), in_mode);
260         BOOST_CHECK_MESSAGE(
261             compare_streams_in_chunks(first, second),
262             "failed reading from half-open restriction<Filter> "
263             "with small padding"
264         );
265     }
266
267     {
268         restricted_test_file   src1(large_padding, true);
269         uppercase_file         src2;
270         stream_offset          off = large_padding;
271         filtering_istream      first;
272         first.push(BOOST_RESTRICT(toupper_filter(), off));
273         first.push(file_source(src1.name(), in_mode));
274         ifstream           second(src2.name().c_str(), in_mode);
275         BOOST_CHECK_MESSAGE(
276             compare_streams_in_chunks(first, second),
277             "failed reading from half-open restriction<Filter> "
278             "with large padding"
279         );
280     }
281 }
282
283 void write_device() 
284 {
285     {
286         restricted_uppercase_file  dest1(small_padding);
287         restricted_test_file       dest2(small_padding);
288         stream_offset              off = small_padding,
289                                    len = data_reps * data_length();
290         filtering_ostream          out(
291             BOOST_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off, len));
292         write_data_in_chunks(out);
293         out.reset();
294         ifstream                   first(dest1.name().c_str(), in_mode);
295         ifstream                   second(dest2.name().c_str(), in_mode);
296         BOOST_CHECK_MESSAGE(
297             compare_streams_in_chunks(first, second),
298             "failed writing to restriction<Device> with small padding"
299         );
300     }
301
302     {
303         restricted_uppercase_file  dest1(large_padding);
304         restricted_test_file       dest2(large_padding);
305         stream_offset              off = large_padding,
306                                    len = data_reps * data_length();
307         filtering_ostream          out
308             (BOOST_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off, len));
309         write_data_in_chunks(out);
310         out.reset();
311         ifstream                   first(dest1.name().c_str(), in_mode);
312         ifstream                   second(dest2.name().c_str(), in_mode);
313         BOOST_CHECK_MESSAGE(
314             compare_streams_in_chunks(first, second),
315             "failed writing to restriction<Device> with large padding"
316         );
317     }
318
319     {
320         restricted_uppercase_file  dest1(small_padding, true);
321         restricted_test_file       dest2(small_padding, true);
322         stream_offset              off = small_padding;
323         filtering_ostream          out
324             (BOOST_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off));
325         write_data_in_chunks(out);
326         out.reset();
327         ifstream                   first(dest1.name().c_str(), in_mode);
328         ifstream                   second(dest2.name().c_str(), in_mode);
329         BOOST_CHECK_MESSAGE(
330             compare_streams_in_chunks(first, second),
331             "failed writing to half-open restriction<Device> "
332             "with small padding"
333         );
334     }
335
336     {
337         restricted_uppercase_file  dest1(large_padding, true);
338         restricted_test_file       dest2(large_padding, true);
339         stream_offset              off = large_padding;
340         filtering_ostream          out
341             (BOOST_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off));
342         write_data_in_chunks(out);
343         out.reset();
344         ifstream                   first(dest1.name().c_str(), in_mode);
345         ifstream                   second(dest2.name().c_str(), in_mode);
346         BOOST_CHECK_MESSAGE(
347             compare_streams_in_chunks(first, second),
348             "failed writing to half-open restriction<Device> "
349             "with large padding"
350         );
351     }
352 }
353
354 void write_direct_device() 
355 {
356     {
357         vector<char>              dest1( data_reps * data_length() + 
358                                          2 * small_padding, 
359                                          '\n' );
360         restricted_test_sequence  dest2(small_padding);
361         stream_offset             off = small_padding,
362                                   len = data_reps * data_length();
363         array_sink                array(&dest1[0], &dest1[0] + dest1.size());
364         filtering_ostream         out(BOOST_RESTRICT(array, off, len));
365         write_data_in_chunks(out);
366         out.reset();
367         BOOST_CHECK_MESSAGE(
368             std::equal(dest1.begin(), dest1.end(), dest2.begin()),
369             "failed writing to restriction<Direct>"
370         );
371     }
372
373     {
374         vector<char>              dest1(
375             data_reps * data_length() + small_padding, '\n');
376         restricted_test_sequence  dest2(small_padding, true);
377         stream_offset             off = small_padding;
378         array_sink                array(&dest1[0], &dest1[0] + dest1.size());
379         filtering_ostream         out(BOOST_RESTRICT(array, off));
380         write_data_in_chunks(out);
381         out.reset();
382         BOOST_CHECK_MESSAGE(
383             std::equal(dest1.begin(), dest1.end(), dest2.begin()),
384             "failed writing to half-open restriction<Direct>"
385         );
386     }
387 }
388
389 void write_filter() 
390 {
391     {
392         restricted_test_file       dest1(small_padding);
393         restricted_lowercase_file  dest2(small_padding);
394         stream_offset              off = small_padding,
395                                    len = data_reps * data_length();
396         filtering_ostream          out;
397         out.push(BOOST_RESTRICT(tolower_seekable_filter(), off, len));
398         out.push(file(dest1.name(), BOOST_IOS::binary));
399         write_data_in_chunks(out);
400         out.reset();
401         ifstream               first(dest1.name().c_str(), in_mode);
402         ifstream               second(dest2.name().c_str(), in_mode);
403         BOOST_CHECK_MESSAGE(
404             compare_streams_in_chunks(first, second),
405             "failed writing to restriction<Filter> with small padding"
406         );
407     }
408
409     {
410         restricted_test_file       dest1(large_padding);
411         restricted_lowercase_file  dest2(large_padding);
412         stream_offset              off = large_padding,
413                                    len = data_reps * data_length();
414         filtering_ostream          out;
415         out.push(BOOST_RESTRICT(tolower_seekable_filter(), off, len));
416         out.push(file(dest1.name(), BOOST_IOS::binary));
417         write_data_in_chunks(out);
418         out.reset();
419         ifstream               first(dest1.name().c_str(), in_mode);
420         ifstream               second(dest2.name().c_str(), in_mode);
421         BOOST_CHECK_MESSAGE(
422             compare_streams_in_chunks(first, second),
423             "failed writing to restriction<Filter> with large padding"
424         );
425     }
426
427     {
428         restricted_test_file       dest1(small_padding, true);
429         restricted_lowercase_file  dest2(small_padding, true);
430         stream_offset              off = small_padding;
431         filtering_ostream          out;
432         out.push(BOOST_RESTRICT(tolower_seekable_filter(), off));
433         out.push(file(dest1.name(), BOOST_IOS::binary));
434         write_data_in_chunks(out);
435         out.reset();
436         ifstream               first(dest1.name().c_str(), in_mode);
437         ifstream               second(dest2.name().c_str(), in_mode);
438         BOOST_CHECK_MESSAGE(
439             compare_streams_in_chunks(first, second),
440             "failed writing to restriction<Filter> with small padding"
441         );
442     }
443
444     {
445         restricted_test_file       dest1(large_padding, true);
446         restricted_lowercase_file  dest2(large_padding, true);
447         stream_offset              off = large_padding;
448         filtering_ostream          out;
449         out.push(BOOST_RESTRICT(tolower_seekable_filter(), off));
450         out.push(file(dest1.name(), BOOST_IOS::binary));
451         write_data_in_chunks(out);
452         out.reset();
453         ifstream                   first(dest1.name().c_str(), in_mode);
454         ifstream                   second(dest2.name().c_str(), in_mode);
455         BOOST_CHECK_MESSAGE(
456             compare_streams_in_chunks(first, second),
457             "failed writing to restriction<Filter> with large padding"
458         );
459     }
460 }
461
462 void seek_device()
463 {
464     {
465         restricted_test_file       src(large_padding);
466         stream_offset              off = large_padding,
467                                    len = data_reps * data_length();
468         filtering_stream<seekable> io(
469             BOOST_RESTRICT(file(src.name(), BOOST_IOS::binary), off, len));
470         BOOST_CHECK_MESSAGE(
471             test_seekable_in_chunks(io),
472             "failed seeking within restriction<Device>"
473         );
474     }
475
476     {
477         restricted_test_file       src(large_padding, true);
478         stream_offset              off = large_padding;
479         filtering_stream<seekable> io(
480             BOOST_RESTRICT(file(src.name(), BOOST_IOS::binary), off));
481         BOOST_CHECK_MESSAGE(
482             test_seekable_in_chunks(io),
483             "failed seeking within half-open restriction<Device>"
484         );
485     }
486 }
487
488 void seek_direct_device()
489 {
490     {
491         vector<char>               src(
492             data_reps * data_length() + 2 * small_padding, '\n');
493         stream_offset              off = small_padding,
494                                    len = data_reps * data_length();
495         array                      ar(&src[0], &src[0] + src.size());
496         filtering_stream<seekable> io(BOOST_RESTRICT(ar, off, len));
497         BOOST_CHECK_MESSAGE(
498             test_seekable_in_chars(io),
499             "failed seeking within restriction<Direct> with small padding"
500         );
501     }
502
503     {
504         vector<char>               src(
505             data_reps * data_length() + small_padding, '\n');
506         stream_offset              off = small_padding;
507         array                      ar(&src[0], &src[0] + src.size());
508         filtering_stream<seekable> io(BOOST_RESTRICT(ar, off));
509         BOOST_CHECK_MESSAGE(
510             test_seekable_in_chars(io),
511             "failed seeking within half-open restriction<Direct> "
512             "with small padding"
513         );
514     }
515 }
516
517 void seek_filter()
518 {
519     {
520         restricted_test_file       src(small_padding);
521         stream_offset              off = large_padding,
522                                    len = data_reps * data_length();
523         filtering_stream<seekable> io;
524         io.push(BOOST_RESTRICT(identity_seekable_filter(), off, len));
525         io.push(file(src.name(), BOOST_IOS::binary));
526         BOOST_CHECK_MESSAGE(
527             test_seekable_in_chars(io),
528             "failed seeking within restriction<Device>"
529         );
530     }
531
532     {
533         restricted_test_file       src(small_padding, true);
534         stream_offset              off = large_padding;
535         filtering_stream<seekable> io;
536         io.push(BOOST_RESTRICT(identity_seekable_filter(), off));
537         io.push(file(src.name(), BOOST_IOS::binary));
538         BOOST_CHECK_MESSAGE(
539             test_seekable_in_chars(io),
540             "failed seeking within half-open restriction<Device>"
541         );
542     }
543 }
544
545 void close_device()
546 {
547     // Restrict a source
548     {
549         operation_sequence  seq;
550         chain<input>        ch;
551         ch.push(
552             io::BOOST_RESTRICT(
553                 closable_device<input>(seq.new_operation(1)), 
554                 0
555             )
556         );
557         BOOST_CHECK_NO_THROW(ch.reset());
558         BOOST_CHECK_OPERATION_SEQUENCE(seq);
559     }
560
561     // Restrict a seekable device
562     {
563         operation_sequence  seq;
564         chain<seekable>     ch;
565         ch.push(
566             io::BOOST_RESTRICT(
567                 closable_device<seekable>(seq.new_operation(1)), 
568                 0
569             )
570         );
571         BOOST_CHECK_NO_THROW(ch.reset());
572         BOOST_CHECK_OPERATION_SEQUENCE(seq);
573     }
574
575     // Restrict a direct source
576     {
577         operation_sequence  seq;
578         chain<input>        ch;
579         ch.push(
580             io::BOOST_RESTRICT(
581                 closable_device<direct_input>(seq.new_operation(1)), 
582                 0
583             )
584         );
585         BOOST_CHECK_NO_THROW(ch.reset());
586         BOOST_CHECK_OPERATION_SEQUENCE(seq);
587     }
588
589     // Restrict a direct seekable device
590     {
591         operation_sequence  seq;
592         chain<seekable>     ch;
593         ch.push(
594             io::BOOST_RESTRICT(
595                 closable_device<direct_seekable>(seq.new_operation(1)), 
596                 0
597             )
598         );
599         BOOST_CHECK_NO_THROW(ch.reset());
600         BOOST_CHECK_OPERATION_SEQUENCE(seq);
601     }
602 }
603
604 void close_filter()
605 {
606     // Restrict an input filter
607     {
608         operation_sequence  seq;
609         chain<input>        ch;
610         ch.push(
611             io::BOOST_RESTRICT(
612                 closable_filter<input>(seq.new_operation(2)), 
613                 0
614             )
615         );
616         ch.push(closable_device<input>(seq.new_operation(1)));
617         BOOST_CHECK_NO_THROW(ch.reset());
618         BOOST_CHECK_OPERATION_SEQUENCE(seq);
619     }
620
621     // Restrict a seekable filter
622     {
623         operation_sequence  seq;
624         chain<seekable>     ch;
625         ch.push(
626             io::BOOST_RESTRICT(
627                 closable_filter<seekable>(seq.new_operation(1)), 
628                 0
629             )
630         );
631         ch.push(closable_device<seekable>(seq.new_operation(2)));
632         BOOST_CHECK_NO_THROW(ch.reset());
633         BOOST_CHECK_OPERATION_SEQUENCE(seq);
634     }
635
636     // Restrict a dual_use filter for input
637     {
638         operation_sequence  seq;
639         chain<input>        ch;
640         operation           dummy;
641         ch.push(
642             io::BOOST_RESTRICT(
643                 closable_filter<dual_use>(
644                     seq.new_operation(2),
645                     dummy
646                 ),
647                 0
648             )
649         );
650         ch.push(closable_device<input>(seq.new_operation(1)));
651         BOOST_CHECK_NO_THROW(ch.reset());
652         BOOST_CHECK_OPERATION_SEQUENCE(seq);
653     }
654
655     // Restrict a dual_use filter for output
656     {
657         operation_sequence  seq;
658         chain<output>       ch;
659         operation           dummy;
660         ch.push(
661             io::BOOST_RESTRICT(
662                 closable_filter<dual_use>(
663                     dummy,
664                     seq.new_operation(1)
665                 ),
666                 0
667             )
668         );
669         ch.push(closable_device<output>(seq.new_operation(2)));
670         BOOST_CHECK_NO_THROW(ch.reset());
671         BOOST_CHECK_OPERATION_SEQUENCE(seq);
672     }
673 }
674
675 test_suite* init_unit_test_suite(int, char* []) 
676 {
677     test_suite* test = 
678         BOOST_TEST_SUITE(BOOST_STRINGIZE(BOOST_RESTRICT) " test");
679     test->add(BOOST_TEST_CASE(&read_device));
680     test->add(BOOST_TEST_CASE(&read_direct_device));
681     test->add(BOOST_TEST_CASE(&read_filter));
682     test->add(BOOST_TEST_CASE(&write_device));
683     test->add(BOOST_TEST_CASE(&write_direct_device));
684     test->add(BOOST_TEST_CASE(&write_filter));
685     test->add(BOOST_TEST_CASE(&seek_device));
686     test->add(BOOST_TEST_CASE(&seek_direct_device));
687     test->add(BOOST_TEST_CASE(&close_device));
688     test->add(BOOST_TEST_CASE(&close_filter));
689     return test;
690 }