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.)
6 // See http://www.boost.org/libs/iostreams for documentation.
8 // Allow this file to be used by slice_test.hpp. It is important not to
9 // replace BOOST_IOSTREAMS_RESTRICT with BOOST_IOSTREAMS_RESTRICT here, since that
10 // would interfere with the oepration of the header
11 // <boost/iostreams/restrict.hpp>
14 #if defined(BOOST_IOSTREAMS_RESTRICT_USE_SLICE)
15 # include <boost/iostreams/slice.hpp>
16 # define BOOST_IOSTREAMS_RESTRICT slice
18 # include <boost/iostreams/restrict.hpp>
19 # define BOOST_IOSTREAMS_RESTRICT restrict
22 #include <algorithm> // equal.
24 #include <iterator> // back_inserter.
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"
41 using namespace boost::iostreams
;
42 using namespace boost::iostreams::test
;
43 using boost::unit_test::test_suite
;
44 namespace io
= boost::iostreams
;
46 const char pad_char
= '\n';
47 const int small_padding
= 50;
48 const int large_padding
= default_device_buffer_size
+ 50;
50 void write_padding(std::ofstream
& out
, int len
)
52 for (int z
= 0; z
< len
; ++z
)
56 struct restricted_test_file
: public temp_file
{
57 restricted_test_file(int padding
, bool half_open
= false)
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());
67 write_padding(f
, padding
);
71 struct restricted_test_sequence
: public std::vector
<char> {
72 restricted_test_sequence(int padding
, bool half_open
= false)
74 for (int z
= 0; z
< padding
; ++z
)
76 const char* buf
= narrow_data();
77 for (int w
= 0; w
< data_reps
; ++w
)
78 insert(end(), buf
, buf
+ data_length());
80 for (int x
= 0; x
< padding
; ++x
)
85 struct restricted_uppercase_file
: public temp_file
{
86 restricted_uppercase_file(int padding
, bool half_open
= false)
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
]));
97 write_padding(f
, padding
);
101 struct restricted_lowercase_file
: public temp_file
{
102 restricted_lowercase_file(int padding
, bool half_open
= false)
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
]));
113 write_padding(f
, padding
);
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
;
124 template<typename Sink
>
125 bool put(Sink
& s
, char c
)
126 { return boost::iostreams::put(s
, (char) std::tolower(c
)); }
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
); }
136 restricted_test_file
src1(small_padding
);
138 stream_offset off
= small_padding
,
139 len
= data_reps
* data_length();
140 filtering_istream
first(
141 BOOST_IOSTREAMS_RESTRICT(file_source(src1
.name(), in_mode
), off
, len
));
142 ifstream
second(src2
.name().c_str(), in_mode
);
144 compare_streams_in_chunks(first
, second
),
145 "failed reading from restriction<Device> with small padding"
150 restricted_test_file
src1(large_padding
);
152 stream_offset off
= large_padding
,
153 len
= data_reps
* data_length();
154 filtering_istream
first(
155 BOOST_IOSTREAMS_RESTRICT(file_source(src1
.name(), in_mode
), off
, len
));
156 ifstream
second(src2
.name().c_str(), in_mode
);
158 compare_streams_in_chunks(first
, second
),
159 "failed reading from restriction<Device> with large padding"
164 restricted_test_file
src1(small_padding
, true);
166 stream_offset off
= small_padding
;
167 filtering_istream
first(
168 BOOST_IOSTREAMS_RESTRICT(file_source(src1
.name(), in_mode
), off
));
169 ifstream
second(src2
.name().c_str(), in_mode
);
171 compare_streams_in_chunks(first
, second
),
172 "failed reading from half-open restriction<Device> "
178 restricted_test_file
src1(large_padding
, true);
180 stream_offset off
= large_padding
;
181 filtering_istream
first(
182 BOOST_IOSTREAMS_RESTRICT(file_source(src1
.name(), in_mode
), off
));
183 ifstream
second(src2
.name().c_str(), in_mode
);
185 compare_streams_in_chunks(first
, second
),
186 "failed reading from half-open restriction<Device> "
192 void read_direct_device()
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_IOSTREAMS_RESTRICT(array_src
, off
, len
));
202 compare_container_and_stream(first
, second
),
203 "failed reading from restriction<Direct>"
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_IOSTREAMS_RESTRICT(array_src
, off
));
214 compare_container_and_stream(first
, second
),
215 "failed reading from half-open restriction<Direct>"
223 restricted_test_file
src1(small_padding
);
225 stream_offset off
= small_padding
,
226 len
= data_reps
* data_length();
227 filtering_istream first
;
228 first
.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off
, len
));
229 first
.push(file_source(src1
.name(), in_mode
));
230 ifstream
second(src2
.name().c_str(), in_mode
);
232 compare_streams_in_chunks(first
, second
),
233 "failed reading from restriction<Filter> with small padding"
238 restricted_test_file
src1(large_padding
);
240 stream_offset off
= large_padding
,
241 len
= data_reps
* data_length();
242 filtering_istream first
;
243 first
.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off
, len
));
244 first
.push(file_source(src1
.name(), in_mode
));
245 ifstream
second(src2
.name().c_str(), in_mode
);
247 compare_streams_in_chunks(first
, second
),
248 "failed reading from restriction<Filter> with large padding"
253 restricted_test_file
src1(small_padding
, true);
255 stream_offset off
= small_padding
;
256 filtering_istream first
;
257 first
.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off
));
258 first
.push(file_source(src1
.name(), in_mode
));
259 ifstream
second(src2
.name().c_str(), in_mode
);
261 compare_streams_in_chunks(first
, second
),
262 "failed reading from half-open restriction<Filter> "
268 restricted_test_file
src1(large_padding
, true);
270 stream_offset off
= large_padding
;
271 filtering_istream first
;
272 first
.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off
));
273 first
.push(file_source(src1
.name(), in_mode
));
274 ifstream
second(src2
.name().c_str(), in_mode
);
276 compare_streams_in_chunks(first
, second
),
277 "failed reading from half-open restriction<Filter> "
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_IOSTREAMS_RESTRICT(file(dest1
.name(), BOOST_IOS::binary
), off
, len
));
292 write_data_in_chunks(out
);
294 ifstream
first(dest1
.name().c_str(), in_mode
);
295 ifstream
second(dest2
.name().c_str(), in_mode
);
297 compare_streams_in_chunks(first
, second
),
298 "failed writing to restriction<Device> with small padding"
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_IOSTREAMS_RESTRICT(file(dest1
.name(), BOOST_IOS::binary
), off
, len
));
309 write_data_in_chunks(out
);
311 ifstream
first(dest1
.name().c_str(), in_mode
);
312 ifstream
second(dest2
.name().c_str(), in_mode
);
314 compare_streams_in_chunks(first
, second
),
315 "failed writing to restriction<Device> with large padding"
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_IOSTREAMS_RESTRICT(file(dest1
.name(), BOOST_IOS::binary
), off
));
325 write_data_in_chunks(out
);
327 ifstream
first(dest1
.name().c_str(), in_mode
);
328 ifstream
second(dest2
.name().c_str(), in_mode
);
330 compare_streams_in_chunks(first
, second
),
331 "failed writing to half-open restriction<Device> "
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_IOSTREAMS_RESTRICT(file(dest1
.name(), BOOST_IOS::binary
), off
));
342 write_data_in_chunks(out
);
344 ifstream
first(dest1
.name().c_str(), in_mode
);
345 ifstream
second(dest2
.name().c_str(), in_mode
);
347 compare_streams_in_chunks(first
, second
),
348 "failed writing to half-open restriction<Device> "
354 void write_direct_device()
357 vector
<char> dest1( data_reps
* data_length() +
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_IOSTREAMS_RESTRICT(array
, off
, len
));
365 write_data_in_chunks(out
);
368 std::equal(dest1
.begin(), dest1
.end(), dest2
.begin()),
369 "failed writing to restriction<Direct>"
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_IOSTREAMS_RESTRICT(array
, off
));
380 write_data_in_chunks(out
);
383 std::equal(dest1
.begin(), dest1
.end(), dest2
.begin()),
384 "failed writing to half-open restriction<Direct>"
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_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off
, len
));
398 out
.push(file(dest1
.name(), BOOST_IOS::binary
));
399 write_data_in_chunks(out
);
401 ifstream
first(dest1
.name().c_str(), in_mode
);
402 ifstream
second(dest2
.name().c_str(), in_mode
);
404 compare_streams_in_chunks(first
, second
),
405 "failed writing to restriction<Filter> with small padding"
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_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off
, len
));
416 out
.push(file(dest1
.name(), BOOST_IOS::binary
));
417 write_data_in_chunks(out
);
419 ifstream
first(dest1
.name().c_str(), in_mode
);
420 ifstream
second(dest2
.name().c_str(), in_mode
);
422 compare_streams_in_chunks(first
, second
),
423 "failed writing to restriction<Filter> with large padding"
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_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off
));
433 out
.push(file(dest1
.name(), BOOST_IOS::binary
));
434 write_data_in_chunks(out
);
436 ifstream
first(dest1
.name().c_str(), in_mode
);
437 ifstream
second(dest2
.name().c_str(), in_mode
);
439 compare_streams_in_chunks(first
, second
),
440 "failed writing to restriction<Filter> with small padding"
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_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off
));
450 out
.push(file(dest1
.name(), BOOST_IOS::binary
));
451 write_data_in_chunks(out
);
453 ifstream
first(dest1
.name().c_str(), in_mode
);
454 ifstream
second(dest2
.name().c_str(), in_mode
);
456 compare_streams_in_chunks(first
, second
),
457 "failed writing to restriction<Filter> with large padding"
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_IOSTREAMS_RESTRICT(file(src
.name(), BOOST_IOS::binary
), off
, len
));
471 test_seekable_in_chunks(io
),
472 "failed seeking within restriction<Device>"
477 restricted_test_file
src(large_padding
, true);
478 stream_offset off
= large_padding
;
479 filtering_stream
<seekable
> io(
480 BOOST_IOSTREAMS_RESTRICT(file(src
.name(), BOOST_IOS::binary
), off
));
482 test_seekable_in_chunks(io
),
483 "failed seeking within half-open restriction<Device>"
488 void seek_direct_device()
492 data_reps
* data_length() + 2 * small_padding
, '\n');
493 stream_offset off
= small_padding
,
494 len
= data_reps
* data_length();
495 io::array
ar(&src
[0], &src
[0] + src
.size());
496 filtering_stream
<seekable
> io(BOOST_IOSTREAMS_RESTRICT(ar
, off
, len
));
498 test_seekable_in_chars(io
),
499 "failed seeking within restriction<Direct> with small padding"
505 data_reps
* data_length() + small_padding
, '\n');
506 stream_offset off
= small_padding
;
507 io::array
ar(&src
[0], &src
[0] + src
.size());
508 filtering_stream
<seekable
> io(BOOST_IOSTREAMS_RESTRICT(ar
, off
));
510 test_seekable_in_chars(io
),
511 "failed seeking within half-open restriction<Direct> "
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_IOSTREAMS_RESTRICT(identity_seekable_filter(), off
, len
));
525 io
.push(file(src
.name(), BOOST_IOS::binary
));
527 test_seekable_in_chars(io
),
528 "failed seeking within restriction<Device>"
533 restricted_test_file
src(small_padding
, true);
534 stream_offset off
= large_padding
;
535 filtering_stream
<seekable
> io
;
536 io
.push(BOOST_IOSTREAMS_RESTRICT(identity_seekable_filter(), off
));
537 io
.push(file(src
.name(), BOOST_IOS::binary
));
539 test_seekable_in_chars(io
),
540 "failed seeking within half-open restriction<Device>"
549 operation_sequence seq
;
552 io::BOOST_IOSTREAMS_RESTRICT(
553 closable_device
<input
>(seq
.new_operation(1)),
557 BOOST_CHECK_NO_THROW(ch
.reset());
558 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
561 // Restrict a seekable device
563 operation_sequence seq
;
566 io::BOOST_IOSTREAMS_RESTRICT(
567 closable_device
<seekable
>(seq
.new_operation(1)),
571 BOOST_CHECK_NO_THROW(ch
.reset());
572 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
575 // Restrict a direct source
577 operation_sequence seq
;
580 io::BOOST_IOSTREAMS_RESTRICT(
581 closable_device
<direct_input
>(seq
.new_operation(1)),
585 BOOST_CHECK_NO_THROW(ch
.reset());
586 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
589 // Restrict a direct seekable device
591 operation_sequence seq
;
594 io::BOOST_IOSTREAMS_RESTRICT(
595 closable_device
<direct_seekable
>(seq
.new_operation(1)),
599 BOOST_CHECK_NO_THROW(ch
.reset());
600 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
606 // Restrict an input filter
608 operation_sequence seq
;
611 io::BOOST_IOSTREAMS_RESTRICT(
612 closable_filter
<input
>(seq
.new_operation(2)),
616 ch
.push(closable_device
<input
>(seq
.new_operation(1)));
617 BOOST_CHECK_NO_THROW(ch
.reset());
618 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
621 // Restrict a seekable filter
623 operation_sequence seq
;
626 io::BOOST_IOSTREAMS_RESTRICT(
627 closable_filter
<seekable
>(seq
.new_operation(1)),
631 ch
.push(closable_device
<seekable
>(seq
.new_operation(2)));
632 BOOST_CHECK_NO_THROW(ch
.reset());
633 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
636 // Restrict a dual_use filter for input
638 operation_sequence seq
;
642 io::BOOST_IOSTREAMS_RESTRICT(
643 closable_filter
<dual_use
>(
644 seq
.new_operation(2),
650 ch
.push(closable_device
<input
>(seq
.new_operation(1)));
651 BOOST_CHECK_NO_THROW(ch
.reset());
652 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
655 // Restrict a dual_use filter for output
657 operation_sequence seq
;
661 io::BOOST_IOSTREAMS_RESTRICT(
662 closable_filter
<dual_use
>(
669 ch
.push(closable_device
<output
>(seq
.new_operation(2)));
670 BOOST_CHECK_NO_THROW(ch
.reset());
671 BOOST_CHECK_OPERATION_SEQUENCE(seq
);
675 test_suite
* init_unit_test_suite(int, char* [])
678 BOOST_TEST_SUITE(BOOST_STRINGIZE(BOOST_IOSTREAMS_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
));