// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) // (C) Copyright 2005-2007 Jonathan Turkanis // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) // See http://www.boost.org/libs/iostreams for documentation. // Allow this file to be used by slice_test.hpp. It is important not to // replace BOOST_IOSTREAMS_RESTRICT with BOOST_IOSTREAMS_RESTRICT here, since that // would interfere with the oepration of the header // #include #if defined(BOOST_IOSTREAMS_RESTRICT_USE_SLICE) # include # define BOOST_IOSTREAMS_RESTRICT slice #else # include # define BOOST_IOSTREAMS_RESTRICT restrict #endif #include // equal. #include #include // back_inserter. #include #include #include #include #include #include #include #include "detail/closable.hpp" #include "detail/constants.hpp" #include "detail/filters.hpp" #include "detail/operation_sequence.hpp" #include "detail/sequence.hpp" #include "detail/temp_file.hpp" #include "detail/verification.hpp" using namespace std; using namespace boost::iostreams; using namespace boost::iostreams::test; using boost::unit_test::test_suite; namespace io = boost::iostreams; const char pad_char = '\n'; const int small_padding = 50; const int large_padding = default_device_buffer_size + 50; void write_padding(std::ofstream& out, int len) { for (int z = 0; z < len; ++z) out.put(pad_char); } struct restricted_test_file : public temp_file { restricted_test_file(int padding, bool half_open = false) { BOOST_IOS::openmode mode = BOOST_IOS::out | BOOST_IOS::binary; ::std::ofstream f(name().c_str(), mode); write_padding(f, padding); const char* buf = narrow_data(); for (int z = 0; z < data_reps; ++z) f.write(buf, data_length()); if (!half_open) write_padding(f, padding); } }; struct restricted_test_sequence : public std::vector { restricted_test_sequence(int padding, bool half_open = false) { for (int z = 0; z < padding; ++z) push_back(pad_char); const char* buf = narrow_data(); for (int w = 0; w < data_reps; ++w) insert(end(), buf, buf + data_length()); if (!half_open) for (int x = 0; x < padding; ++x) push_back(pad_char); } }; struct restricted_uppercase_file : public temp_file { restricted_uppercase_file(int padding, bool half_open = false) { BOOST_IOS::openmode mode = BOOST_IOS::out | BOOST_IOS::binary; ::std::ofstream f(name().c_str(), mode); write_padding(f, padding); const char* buf = narrow_data(); for (int z = 0; z < data_reps; ++z) for (int w = 0; w < data_length(); ++w) f.put((char) std::toupper(buf[w])); if (!half_open) write_padding(f, padding); } }; struct restricted_lowercase_file : public temp_file { restricted_lowercase_file(int padding, bool half_open = false) { BOOST_IOS::openmode mode = BOOST_IOS::out | BOOST_IOS::binary; ::std::ofstream f(name().c_str(), mode); write_padding(f, padding); const char* buf = narrow_data(); for (int z = 0; z < data_reps; ++z) for (int w = 0; w < data_length(); ++w) f.put((char) std::tolower(buf[w])); if (!half_open) write_padding(f, padding); } }; // Can't have a restricted view of a non-seekble output filter. struct tolower_seekable_filter : public seekable_filter { typedef char char_type; struct category : output_seekable, filter_tag { }; template bool put(Sink& s, char c) { return boost::iostreams::put(s, (char) std::tolower(c)); } template std::streampos seek(Sink& s, stream_offset off, BOOST_IOS::seekdir way) { return boost::iostreams::seek(s, off, way); } }; void read_device() { { restricted_test_file src1(small_padding); test_file src2; stream_offset off = small_padding, len = data_reps * data_length(); filtering_istream first( BOOST_IOSTREAMS_RESTRICT(file_source(src1.name(), in_mode), off, len)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from restriction with small padding" ); } { restricted_test_file src1(large_padding); test_file src2; stream_offset off = large_padding, len = data_reps * data_length(); filtering_istream first( BOOST_IOSTREAMS_RESTRICT(file_source(src1.name(), in_mode), off, len)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from restriction with large padding" ); } { restricted_test_file src1(small_padding, true); test_file src2; stream_offset off = small_padding; filtering_istream first( BOOST_IOSTREAMS_RESTRICT(file_source(src1.name(), in_mode), off)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from half-open restriction " "with small padding" ); } { restricted_test_file src1(large_padding, true); test_file src2; stream_offset off = large_padding; filtering_istream first( BOOST_IOSTREAMS_RESTRICT(file_source(src1.name(), in_mode), off)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from half-open restriction " "with large padding" ); } } void read_direct_device() { { test_sequence first; restricted_test_sequence src(small_padding); array_source array_src(&src[0], &src[0] + src.size()); stream_offset off = small_padding, len = data_reps * data_length(); filtering_istream second(BOOST_IOSTREAMS_RESTRICT(array_src, off, len)); BOOST_CHECK_MESSAGE( compare_container_and_stream(first, second), "failed reading from restriction" ); } { test_sequence first; restricted_test_sequence src(small_padding, true); array_source array_src(&src[0], &src[0] + src.size()); stream_offset off = small_padding; filtering_istream second(BOOST_IOSTREAMS_RESTRICT(array_src, off)); BOOST_CHECK_MESSAGE( compare_container_and_stream(first, second), "failed reading from half-open restriction" ); } } void read_filter() { { restricted_test_file src1(small_padding); uppercase_file src2; stream_offset off = small_padding, len = data_reps * data_length(); filtering_istream first; first.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off, len)); first.push(file_source(src1.name(), in_mode)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from restriction with small padding" ); } { restricted_test_file src1(large_padding); uppercase_file src2; stream_offset off = large_padding, len = data_reps * data_length(); filtering_istream first; first.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off, len)); first.push(file_source(src1.name(), in_mode)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from restriction with large padding" ); } { restricted_test_file src1(small_padding, true); uppercase_file src2; stream_offset off = small_padding; filtering_istream first; first.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off)); first.push(file_source(src1.name(), in_mode)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from half-open restriction " "with small padding" ); } { restricted_test_file src1(large_padding, true); uppercase_file src2; stream_offset off = large_padding; filtering_istream first; first.push(BOOST_IOSTREAMS_RESTRICT(toupper_filter(), off)); first.push(file_source(src1.name(), in_mode)); ifstream second(src2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed reading from half-open restriction " "with large padding" ); } } void write_device() { { restricted_uppercase_file dest1(small_padding); restricted_test_file dest2(small_padding); stream_offset off = small_padding, len = data_reps * data_length(); filtering_ostream out( BOOST_IOSTREAMS_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off, len)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with small padding" ); } { restricted_uppercase_file dest1(large_padding); restricted_test_file dest2(large_padding); stream_offset off = large_padding, len = data_reps * data_length(); filtering_ostream out (BOOST_IOSTREAMS_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off, len)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with large padding" ); } { restricted_uppercase_file dest1(small_padding, true); restricted_test_file dest2(small_padding, true); stream_offset off = small_padding; filtering_ostream out (BOOST_IOSTREAMS_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to half-open restriction " "with small padding" ); } { restricted_uppercase_file dest1(large_padding, true); restricted_test_file dest2(large_padding, true); stream_offset off = large_padding; filtering_ostream out (BOOST_IOSTREAMS_RESTRICT(file(dest1.name(), BOOST_IOS::binary), off)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to half-open restriction " "with large padding" ); } } void write_direct_device() { { vector dest1( data_reps * data_length() + 2 * small_padding, '\n' ); restricted_test_sequence dest2(small_padding); stream_offset off = small_padding, len = data_reps * data_length(); array_sink array(&dest1[0], &dest1[0] + dest1.size()); filtering_ostream out(BOOST_IOSTREAMS_RESTRICT(array, off, len)); write_data_in_chunks(out); out.reset(); BOOST_CHECK_MESSAGE( std::equal(dest1.begin(), dest1.end(), dest2.begin()), "failed writing to restriction" ); } { vector dest1( data_reps * data_length() + small_padding, '\n'); restricted_test_sequence dest2(small_padding, true); stream_offset off = small_padding; array_sink array(&dest1[0], &dest1[0] + dest1.size()); filtering_ostream out(BOOST_IOSTREAMS_RESTRICT(array, off)); write_data_in_chunks(out); out.reset(); BOOST_CHECK_MESSAGE( std::equal(dest1.begin(), dest1.end(), dest2.begin()), "failed writing to half-open restriction" ); } } void write_filter() { { restricted_test_file dest1(small_padding); restricted_lowercase_file dest2(small_padding); stream_offset off = small_padding, len = data_reps * data_length(); filtering_ostream out; out.push(BOOST_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off, len)); out.push(file(dest1.name(), BOOST_IOS::binary)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with small padding" ); } { restricted_test_file dest1(large_padding); restricted_lowercase_file dest2(large_padding); stream_offset off = large_padding, len = data_reps * data_length(); filtering_ostream out; out.push(BOOST_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off, len)); out.push(file(dest1.name(), BOOST_IOS::binary)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with large padding" ); } { restricted_test_file dest1(small_padding, true); restricted_lowercase_file dest2(small_padding, true); stream_offset off = small_padding; filtering_ostream out; out.push(BOOST_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off)); out.push(file(dest1.name(), BOOST_IOS::binary)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with small padding" ); } { restricted_test_file dest1(large_padding, true); restricted_lowercase_file dest2(large_padding, true); stream_offset off = large_padding; filtering_ostream out; out.push(BOOST_IOSTREAMS_RESTRICT(tolower_seekable_filter(), off)); out.push(file(dest1.name(), BOOST_IOS::binary)); write_data_in_chunks(out); out.reset(); ifstream first(dest1.name().c_str(), in_mode); ifstream second(dest2.name().c_str(), in_mode); BOOST_CHECK_MESSAGE( compare_streams_in_chunks(first, second), "failed writing to restriction with large padding" ); } } void seek_device() { { restricted_test_file src(large_padding); stream_offset off = large_padding, len = data_reps * data_length(); filtering_stream io( BOOST_IOSTREAMS_RESTRICT(file(src.name(), BOOST_IOS::binary), off, len)); BOOST_CHECK_MESSAGE( test_seekable_in_chunks(io), "failed seeking within restriction" ); } { restricted_test_file src(large_padding, true); stream_offset off = large_padding; filtering_stream io( BOOST_IOSTREAMS_RESTRICT(file(src.name(), BOOST_IOS::binary), off)); BOOST_CHECK_MESSAGE( test_seekable_in_chunks(io), "failed seeking within half-open restriction" ); } } void seek_direct_device() { { vector src( data_reps * data_length() + 2 * small_padding, '\n'); stream_offset off = small_padding, len = data_reps * data_length(); io::array ar(&src[0], &src[0] + src.size()); filtering_stream io(BOOST_IOSTREAMS_RESTRICT(ar, off, len)); BOOST_CHECK_MESSAGE( test_seekable_in_chars(io), "failed seeking within restriction with small padding" ); } { vector src( data_reps * data_length() + small_padding, '\n'); stream_offset off = small_padding; io::array ar(&src[0], &src[0] + src.size()); filtering_stream io(BOOST_IOSTREAMS_RESTRICT(ar, off)); BOOST_CHECK_MESSAGE( test_seekable_in_chars(io), "failed seeking within half-open restriction " "with small padding" ); } } void seek_filter() { { restricted_test_file src(small_padding); stream_offset off = large_padding, len = data_reps * data_length(); filtering_stream io; io.push(BOOST_IOSTREAMS_RESTRICT(identity_seekable_filter(), off, len)); io.push(file(src.name(), BOOST_IOS::binary)); BOOST_CHECK_MESSAGE( test_seekable_in_chars(io), "failed seeking within restriction" ); } { restricted_test_file src(small_padding, true); stream_offset off = large_padding; filtering_stream io; io.push(BOOST_IOSTREAMS_RESTRICT(identity_seekable_filter(), off)); io.push(file(src.name(), BOOST_IOS::binary)); BOOST_CHECK_MESSAGE( test_seekable_in_chars(io), "failed seeking within half-open restriction" ); } } void close_device() { // Restrict a source { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_device(seq.new_operation(1)), 0 ) ); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a seekable device { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_device(seq.new_operation(1)), 0 ) ); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a direct source { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_device(seq.new_operation(1)), 0 ) ); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a direct seekable device { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_device(seq.new_operation(1)), 0 ) ); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } } void close_filter() { // Restrict an input filter { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_filter(seq.new_operation(2)), 0 ) ); ch.push(closable_device(seq.new_operation(1))); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a seekable filter { operation_sequence seq; chain ch; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_filter(seq.new_operation(1)), 0 ) ); ch.push(closable_device(seq.new_operation(2))); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a dual_use filter for input { operation_sequence seq; chain ch; operation dummy; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_filter( seq.new_operation(2), dummy ), 0 ) ); ch.push(closable_device(seq.new_operation(1))); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } // Restrict a dual_use filter for output { operation_sequence seq; chain ch; operation dummy; ch.push( io::BOOST_IOSTREAMS_RESTRICT( closable_filter( dummy, seq.new_operation(1) ), 0 ) ); ch.push(closable_device(seq.new_operation(2))); BOOST_CHECK_NO_THROW(ch.reset()); BOOST_CHECK_OPERATION_SEQUENCE(seq); } } test_suite* init_unit_test_suite(int, char* []) { test_suite* test = BOOST_TEST_SUITE(BOOST_STRINGIZE(BOOST_IOSTREAMS_RESTRICT) " test"); test->add(BOOST_TEST_CASE(&read_device)); test->add(BOOST_TEST_CASE(&read_direct_device)); test->add(BOOST_TEST_CASE(&read_filter)); test->add(BOOST_TEST_CASE(&write_device)); test->add(BOOST_TEST_CASE(&write_direct_device)); test->add(BOOST_TEST_CASE(&write_filter)); test->add(BOOST_TEST_CASE(&seek_device)); test->add(BOOST_TEST_CASE(&seek_direct_device)); test->add(BOOST_TEST_CASE(&close_device)); test->add(BOOST_TEST_CASE(&close_filter)); return test; }