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_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_RESTRICT_USE_SLICE)
15 # include <boost/iostreams/slice.hpp>
16 # define BOOST_RESTRICT slice
18 # include <boost/iostreams/restrict.hpp>
19 # define BOOST_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 array ar(&src[0], &src[0] + src.size());
496 filtering_stream<seekable> io(BOOST_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 array ar(&src[0], &src[0] + src.size());
508 filtering_stream<seekable> io(BOOST_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_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_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;
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;
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;
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;
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;
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;
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;
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;
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_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));