From 1a78a62555be32868418fe52f8e330c9d0f95d5a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Oct 2012 12:57:26 -0700 Subject: Imported Upstream version 1.49.0 --- libs/iostreams/test/Jamfile.v2 | 152 +++++ libs/iostreams/test/array_test.cpp | 99 +++ libs/iostreams/test/auto_close_test.cpp | 184 ++++++ libs/iostreams/test/bool_trait_test.cpp | 252 ++++++++ libs/iostreams/test/buffer_size_test.cpp | 82 +++ libs/iostreams/test/bzip2_test.cpp | 96 +++ libs/iostreams/test/close_test.cpp | 651 +++++++++++++++++++ libs/iostreams/test/code_converter_test.cpp | 387 ++++++++++++ libs/iostreams/test/combine_test.cpp | 227 +++++++ libs/iostreams/test/component_access_test.cpp | 173 ++++++ libs/iostreams/test/compose_test.cpp | 504 +++++++++++++++ libs/iostreams/test/copy_test.cpp | 172 +++++ libs/iostreams/test/counter_test.cpp | 98 +++ .../test/deprecated_file_descriptor_test.cpp | 243 ++++++++ libs/iostreams/test/detail/closable.hpp | 343 ++++++++++ libs/iostreams/test/detail/constants.hpp | 67 ++ libs/iostreams/test/detail/file_handle.hpp | 108 ++++ libs/iostreams/test/detail/filters.hpp | 186 ++++++ libs/iostreams/test/detail/null_padded_codecvt.hpp | 275 ++++++++ libs/iostreams/test/detail/operation_sequence.hpp | 224 +++++++ libs/iostreams/test/detail/sequence.hpp | 274 ++++++++ libs/iostreams/test/detail/temp_file.hpp | 92 +++ libs/iostreams/test/detail/utf8_codecvt_facet.cpp | 371 +++++++++++ libs/iostreams/test/detail/utf8_codecvt_facet.hpp | 200 ++++++ libs/iostreams/test/detail/verification.hpp | 316 ++++++++++ libs/iostreams/test/direct_adapter_test.cpp | 111 ++++ libs/iostreams/test/example_test.cpp | 461 ++++++++++++++ libs/iostreams/test/execute_test.cpp | 660 ++++++++++++++++++++ libs/iostreams/test/file_descriptor_test.cpp | 642 +++++++++++++++++++ libs/iostreams/test/file_test.cpp | 63 ++ libs/iostreams/test/filter_test.cpp | 98 +++ .../iostreams/test/filtering_stream_flush_test.hpp | 36 ++ libs/iostreams/test/filtering_stream_test.cpp | 52 ++ libs/iostreams/test/finite_state_filter_test.cpp | 182 ++++++ libs/iostreams/test/flush_test.cpp | 145 +++++ libs/iostreams/test/grep_test.cpp | 282 +++++++++ libs/iostreams/test/gzip_test.cpp | 121 ++++ libs/iostreams/test/invert_test.cpp | 70 +++ libs/iostreams/test/large_file_test.cpp | 446 +++++++++++++ libs/iostreams/test/line_filter_test.cpp | 99 +++ libs/iostreams/test/mapped_file_test.cpp | 329 ++++++++++ libs/iostreams/test/newline_test.cpp | 486 +++++++++++++++ libs/iostreams/test/null_test.cpp | 44 ++ libs/iostreams/test/operation_sequence_test.cpp | 268 ++++++++ libs/iostreams/test/path_test.cpp | 25 + libs/iostreams/test/pipeline_test.cpp | 90 +++ libs/iostreams/test/putback_test.hpp | 167 +++++ libs/iostreams/test/read_bidir_filter_test.hpp | 131 ++++ libs/iostreams/test/read_bidir_streambuf_test.hpp | 77 +++ libs/iostreams/test/read_bidir_test.hpp | 85 +++ libs/iostreams/test/read_input_filter_test.hpp | 105 ++++ libs/iostreams/test/read_input_istream_test.hpp | 76 +++ libs/iostreams/test/read_input_seq_test.hpp | 70 +++ libs/iostreams/test/read_input_test.hpp | 65 ++ libs/iostreams/test/read_seekable_seq_test.hpp | 71 +++ libs/iostreams/test/read_seekable_test.hpp | 69 +++ libs/iostreams/test/regex_filter_test.cpp | 329 ++++++++++ libs/iostreams/test/restrict_test.cpp | 690 +++++++++++++++++++++ libs/iostreams/test/seek_test.hpp | 51 ++ libs/iostreams/test/seekable_file_test.cpp | 56 ++ libs/iostreams/test/seekable_filter_test.cpp | 95 +++ libs/iostreams/test/sequence_test.cpp | 24 + libs/iostreams/test/slice_test.cpp | 17 + libs/iostreams/test/stdio_filter_test.cpp | 144 +++++ libs/iostreams/test/stream_offset_32bit_test.cpp | 51 ++ libs/iostreams/test/stream_offset_64bit_test.cpp | 85 +++ libs/iostreams/test/stream_state_test.cpp | 161 +++++ libs/iostreams/test/symmetric_filter_test.cpp | 182 ++++++ libs/iostreams/test/tee_test.cpp | 370 +++++++++++ libs/iostreams/test/wide_stream_test.cpp | 145 +++++ libs/iostreams/test/write_bidir_filter_test.hpp | 134 ++++ libs/iostreams/test/write_bidir_streambuf_test.hpp | 87 +++ libs/iostreams/test/write_bidir_test.hpp | 89 +++ libs/iostreams/test/write_output_filter_test.hpp | 114 ++++ libs/iostreams/test/write_output_iterator_test.hpp | 85 +++ libs/iostreams/test/write_output_ostream_test.hpp | 84 +++ libs/iostreams/test/write_output_seq_test.hpp | 78 +++ libs/iostreams/test/write_output_test.hpp | 73 +++ libs/iostreams/test/write_seekable_seq_test.hpp | 79 +++ libs/iostreams/test/write_seekable_test.hpp | 77 +++ libs/iostreams/test/zlib_test.cpp | 60 ++ 81 files changed, 14762 insertions(+) create mode 100644 libs/iostreams/test/Jamfile.v2 create mode 100644 libs/iostreams/test/array_test.cpp create mode 100644 libs/iostreams/test/auto_close_test.cpp create mode 100644 libs/iostreams/test/bool_trait_test.cpp create mode 100644 libs/iostreams/test/buffer_size_test.cpp create mode 100644 libs/iostreams/test/bzip2_test.cpp create mode 100644 libs/iostreams/test/close_test.cpp create mode 100644 libs/iostreams/test/code_converter_test.cpp create mode 100644 libs/iostreams/test/combine_test.cpp create mode 100644 libs/iostreams/test/component_access_test.cpp create mode 100644 libs/iostreams/test/compose_test.cpp create mode 100644 libs/iostreams/test/copy_test.cpp create mode 100644 libs/iostreams/test/counter_test.cpp create mode 100644 libs/iostreams/test/deprecated_file_descriptor_test.cpp create mode 100644 libs/iostreams/test/detail/closable.hpp create mode 100644 libs/iostreams/test/detail/constants.hpp create mode 100644 libs/iostreams/test/detail/file_handle.hpp create mode 100644 libs/iostreams/test/detail/filters.hpp create mode 100644 libs/iostreams/test/detail/null_padded_codecvt.hpp create mode 100644 libs/iostreams/test/detail/operation_sequence.hpp create mode 100644 libs/iostreams/test/detail/sequence.hpp create mode 100644 libs/iostreams/test/detail/temp_file.hpp create mode 100644 libs/iostreams/test/detail/utf8_codecvt_facet.cpp create mode 100644 libs/iostreams/test/detail/utf8_codecvt_facet.hpp create mode 100644 libs/iostreams/test/detail/verification.hpp create mode 100644 libs/iostreams/test/direct_adapter_test.cpp create mode 100644 libs/iostreams/test/example_test.cpp create mode 100644 libs/iostreams/test/execute_test.cpp create mode 100644 libs/iostreams/test/file_descriptor_test.cpp create mode 100644 libs/iostreams/test/file_test.cpp create mode 100644 libs/iostreams/test/filter_test.cpp create mode 100644 libs/iostreams/test/filtering_stream_flush_test.hpp create mode 100644 libs/iostreams/test/filtering_stream_test.cpp create mode 100644 libs/iostreams/test/finite_state_filter_test.cpp create mode 100644 libs/iostreams/test/flush_test.cpp create mode 100644 libs/iostreams/test/grep_test.cpp create mode 100644 libs/iostreams/test/gzip_test.cpp create mode 100644 libs/iostreams/test/invert_test.cpp create mode 100644 libs/iostreams/test/large_file_test.cpp create mode 100644 libs/iostreams/test/line_filter_test.cpp create mode 100644 libs/iostreams/test/mapped_file_test.cpp create mode 100644 libs/iostreams/test/newline_test.cpp create mode 100644 libs/iostreams/test/null_test.cpp create mode 100644 libs/iostreams/test/operation_sequence_test.cpp create mode 100644 libs/iostreams/test/path_test.cpp create mode 100644 libs/iostreams/test/pipeline_test.cpp create mode 100644 libs/iostreams/test/putback_test.hpp create mode 100644 libs/iostreams/test/read_bidir_filter_test.hpp create mode 100644 libs/iostreams/test/read_bidir_streambuf_test.hpp create mode 100644 libs/iostreams/test/read_bidir_test.hpp create mode 100644 libs/iostreams/test/read_input_filter_test.hpp create mode 100644 libs/iostreams/test/read_input_istream_test.hpp create mode 100644 libs/iostreams/test/read_input_seq_test.hpp create mode 100644 libs/iostreams/test/read_input_test.hpp create mode 100644 libs/iostreams/test/read_seekable_seq_test.hpp create mode 100644 libs/iostreams/test/read_seekable_test.hpp create mode 100644 libs/iostreams/test/regex_filter_test.cpp create mode 100644 libs/iostreams/test/restrict_test.cpp create mode 100644 libs/iostreams/test/seek_test.hpp create mode 100644 libs/iostreams/test/seekable_file_test.cpp create mode 100644 libs/iostreams/test/seekable_filter_test.cpp create mode 100644 libs/iostreams/test/sequence_test.cpp create mode 100644 libs/iostreams/test/slice_test.cpp create mode 100644 libs/iostreams/test/stdio_filter_test.cpp create mode 100644 libs/iostreams/test/stream_offset_32bit_test.cpp create mode 100644 libs/iostreams/test/stream_offset_64bit_test.cpp create mode 100644 libs/iostreams/test/stream_state_test.cpp create mode 100644 libs/iostreams/test/symmetric_filter_test.cpp create mode 100644 libs/iostreams/test/tee_test.cpp create mode 100644 libs/iostreams/test/wide_stream_test.cpp create mode 100644 libs/iostreams/test/write_bidir_filter_test.hpp create mode 100644 libs/iostreams/test/write_bidir_streambuf_test.hpp create mode 100644 libs/iostreams/test/write_bidir_test.hpp create mode 100644 libs/iostreams/test/write_output_filter_test.hpp create mode 100644 libs/iostreams/test/write_output_iterator_test.hpp create mode 100644 libs/iostreams/test/write_output_ostream_test.hpp create mode 100644 libs/iostreams/test/write_output_seq_test.hpp create mode 100644 libs/iostreams/test/write_output_test.hpp create mode 100644 libs/iostreams/test/write_seekable_seq_test.hpp create mode 100644 libs/iostreams/test/write_seekable_test.hpp create mode 100644 libs/iostreams/test/zlib_test.cpp (limited to 'libs/iostreams/test') diff --git a/libs/iostreams/test/Jamfile.v2 b/libs/iostreams/test/Jamfile.v2 new file mode 100644 index 0000000000..794a02de29 --- /dev/null +++ b/libs/iostreams/test/Jamfile.v2 @@ -0,0 +1,152 @@ +# Boost.Iostreams Library test Jamfile + +# (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +# (C) Copyright 2004-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. + +import stlport ; +import modules ; + +local NO_BZIP2 = [ modules.peek : NO_BZIP2 ] ; +local NO_ZLIB = [ modules.peek : NO_ZLIB ] ; +local LARGE_FILE_TEMP = [ modules.peek : LARGE_FILE_TEMP ] ; +local LARGE_FILE_KEEP = [ modules.peek : LARGE_FILE_KEEP ] ; + +rule test-iostreams ( sources * : requirements * : target-name ? ) { + return [ + run + $(sources) + /boost/test//boost_unit_test_framework/static + /boost/filesystem//boost_filesystem/static + : # command + : # input files + : # build requirements + msvc:_CRT_SECURE_NO_DEPRECATE + msvc:_SCL_SECURE_NO_DEPRECATE + cw-9.3,darwin:static + BOOST_IOSTREAMS_NO_LIB + shared:BOOST_IOSTREAMS_DYN_LINK=1 + $(requirements) + : $(target-name) + ] ; +} + +rule compile-fail-iostreams ( sources * : requirements * : target-name ? ) { + return [ + compile-fail + $(sources) + /boost/test//boost_unit_test_framework/static + /boost/filesystem//boost_filesystem/static + : # build requirements + msvc:_CRT_SECURE_NO_DEPRECATE + msvc:_SCL_SECURE_NO_DEPRECATE + cw-9.3,darwin:static + BOOST_IOSTREAMS_NO_LIB + shared:BOOST_IOSTREAMS_DYN_LINK=1 + $(requirements) + : $(target-name) + ] ; +} + + + local all-tests = + [ test-iostreams array_test.cpp ] + [ test-iostreams auto_close_test.cpp ] + [ test-iostreams buffer_size_test.cpp ] + [ test-iostreams close_test.cpp ] + [ test-iostreams + code_converter_test.cpp + detail/utf8_codecvt_facet.cpp ] + [ test-iostreams combine_test.cpp ] + [ test-iostreams compose_test.cpp ] + [ test-iostreams component_access_test.cpp ] + [ test-iostreams copy_test.cpp ] + [ test-iostreams counter_test.cpp ] + [ test-iostreams direct_adapter_test.cpp ] + [ test-iostreams example_test.cpp ] + [ test-iostreams execute_test.cpp ] + [ test-iostreams file_test.cpp ] + [ test-iostreams file_descriptor_test.cpp + ../build//boost_iostreams ] + [ test-iostreams deprecated_file_descriptor_test.cpp + ../build//boost_iostreams + : BOOST_IOSTREAMS_USE_DEPRECATED ] + [ compile-fail-iostreams deprecated_file_descriptor_test.cpp + : + : deprecated_file_descriptor_fail ] + [ test-iostreams filtering_stream_test.cpp ] + [ test-iostreams finite_state_filter_test.cpp ] + [ test-iostreams flush_test.cpp ] + [ test-iostreams + grep_test.cpp + /boost/regex//boost_regex ] + [ test-iostreams invert_test.cpp ] + [ test-iostreams line_filter_test.cpp ] + [ test-iostreams mapped_file_test.cpp + ../build//boost_iostreams ] + [ test-iostreams path_test.cpp + : BOOST_FILESYSTEM_VERSION=2 + : path_test_filesystem2 ] + [ test-iostreams path_test.cpp + : BOOST_FILESYSTEM_VERSION=3 + : path_test_filesystem3 ] + [ test-iostreams newline_test.cpp ] + [ test-iostreams null_test.cpp ] + [ test-iostreams operation_sequence_test.cpp ] + [ test-iostreams pipeline_test.cpp ] + [ test-iostreams + regex_filter_test.cpp + /boost/regex//boost_regex ] + [ test-iostreams restrict_test.cpp ] + [ test-iostreams seekable_file_test.cpp ] + [ test-iostreams seekable_filter_test.cpp ] + [ test-iostreams sequence_test.cpp ] + [ test-iostreams slice_test.cpp ] + [ test-iostreams stdio_filter_test.cpp ] + [ test-iostreams stream_offset_32bit_test.cpp ] + [ test-iostreams stream_offset_64bit_test.cpp ] + #[ test-iostreams stream_state_test.cpp ] + [ test-iostreams symmetric_filter_test.cpp ] + [ test-iostreams tee_test.cpp ] + [ test-iostreams wide_stream_test.cpp ] + ; + + if $(LARGE_FILE_KEEP) + { + all-tests += + [ test-iostreams + large_file_test.cpp + ../src/file_descriptor.cpp + ../src/mapped_file.cpp + : LARGE_FILE_KEEP=$(LARGE_FILE_KEEP) + static ] ; + } + if $(LARGE_FILE_TEMP) + { + all-tests += + [ test-iostreams + large_file_test.cpp + ../src/file_descriptor.cpp + ../src/mapped_file.cpp + : LARGE_FILE_TEMP=$(LARGE_FILE_TEMP) + static ] ; + } + if ! $(NO_BZIP2) + { + all-tests += [ test-iostreams + bzip2_test.cpp ../build//boost_iostreams ] ; + } + if ! $(NO_ZLIB) + { + all-tests += + [ test-iostreams + gzip_test.cpp ../build//boost_iostreams ] + [ test-iostreams + zlib_test.cpp ../build//boost_iostreams ] ; + } + + test-suite "iostreams" : $(all-tests) ; + diff --git a/libs/iostreams/test/array_test.cpp b/libs/iostreams/test/array_test.cpp new file mode 100644 index 0000000000..0ad62bfa81 --- /dev/null +++ b/libs/iostreams/test/array_test.cpp @@ -0,0 +1,99 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using boost::unit_test::test_suite; + +void array_test() +{ + using namespace std; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + //--------------stream-------------------------------// + + { + test_sequence<> seq; + stream first(&seq[0], &seq[0] + seq.size()); + ifstream second(test.name().c_str(), BOOST_IOS::in | BOOST_IOS::binary); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from stream in chars" + ); + } + + { + test_sequence<> seq; + stream first(&seq[0], &seq[0] + seq.size()); + ifstream second(test.name().c_str(), BOOST_IOS::in | BOOST_IOS::binary); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from stream in chunks" + ); + } + + //--------------stream---------------------------------// + + { + vector first(data_reps * data_length(), '?'); + stream out(&first[0], &first[0] + first.size()); + write_data_in_chars(out); + ifstream second(test.name().c_str(), BOOST_IOS::in | BOOST_IOS::binary); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to stream in chars" + ); + } + + { + vector first(data_reps * data_length(), '?'); + stream out(&first[0], &first[0] + first.size()); + write_data_in_chunks(out); + ifstream second(test.name().c_str(), BOOST_IOS::in | BOOST_IOS::binary); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to stream in chunks" + ); + } + + //--------------random access---------------------------------------------// + + { + vector first(data_reps * data_length(), '?'); + stream io(&first[0], &first[0] + first.size()); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within stream, in chars" + ); + } + + { + vector first(data_reps * data_length(), '?'); + stream io(&first[0], &first[0] + first.size()); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within stream, in chunks" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("array test"); + test->add(BOOST_TEST_CASE(&array_test)); + return test; +} diff --git a/libs/iostreams/test/auto_close_test.cpp b/libs/iostreams/test/auto_close_test.cpp new file mode 100644 index 0000000000..fb68022549 --- /dev/null +++ b/libs/iostreams/test/auto_close_test.cpp @@ -0,0 +1,184 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include // EOF. +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +class closable_source : public source { +public: + closable_source() : open_(new bool(true)) { } + std::streamsize read(char*, std::streamsize) { return 0; } + void open() { *open_ = true; } + void close() { *open_ = false; } + bool is_open() const { return *open_; } +private: + boost::shared_ptr open_; +}; + +class closable_input_filter : public input_filter { +public: + closable_input_filter() : open_(new bool(true)) { } + + template + int get(Source&) { return EOF; } + + void open() { *open_ = true; } + + template + void close(Source&) { *open_ = false; } + + bool is_open() const { return *open_; } +private: + boost::shared_ptr open_; +}; + +void auto_close_source() +{ + // Rely on auto_close to close source. + closable_source src; + { + stream in(src); + BOOST_CHECK(src.is_open()); + BOOST_CHECK(in.auto_close()); + } + BOOST_CHECK(!src.is_open()); + + // Use close() to close components. + src.open(); + { + stream in(src); + BOOST_CHECK(src.is_open()); + BOOST_CHECK(in.auto_close()); + in.close(); + BOOST_CHECK(!src.is_open()); + } + + // Use close() to close components, with auto_close disabled. + src.open(); + { + stream in(src); + BOOST_CHECK(src.is_open()); + in.set_auto_close(false); + in.close(); + BOOST_CHECK(!src.is_open()); + } + + // Disable auto_close. + src.open(); + { + stream in(src); + BOOST_CHECK(src.is_open()); + in.set_auto_close(false); + BOOST_CHECK(!in.auto_close()); + } + BOOST_CHECK(src.is_open()); +} + +void auto_close_filter() +{ + closable_source src; + closable_input_filter flt; + + // Rely on auto_close to close components. + { + filtering_istream in; + in.push(flt); + in.push(src); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + BOOST_CHECK(in.auto_close()); + } + BOOST_CHECK(!flt.is_open()); + BOOST_CHECK(!src.is_open()); + + // Use reset() to close components. + flt.open(); + src.open(); + { + filtering_istream in; + in.push(flt); + in.push(src); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + BOOST_CHECK(in.auto_close()); + in.reset(); + BOOST_CHECK(!flt.is_open()); + BOOST_CHECK(!src.is_open()); + } + + // Use reset() to close components, with auto_close disabled. + flt.open(); + src.open(); + { + filtering_istream in; + in.push(flt); + in.push(src); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + in.set_auto_close(false); + in.reset(); + BOOST_CHECK(!flt.is_open()); + BOOST_CHECK(!src.is_open()); + } + + // Disable auto_close. + flt.open(); + src.open(); + { + filtering_istream in; + in.push(flt); + in.push(src); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + in.set_auto_close(false); + BOOST_CHECK(!in.auto_close()); + in.pop(); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + } + BOOST_CHECK(!flt.is_open()); + BOOST_CHECK(src.is_open()); + + // Disable auto_close; disconnect and reconnect resource. + flt.open(); + src.open(); + { + filtering_istream in; + in.push(flt); + in.push(src); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + in.set_auto_close(false); + BOOST_CHECK(!in.auto_close()); + in.pop(); + BOOST_CHECK(flt.is_open()); + BOOST_CHECK(src.is_open()); + in.push(src); + } + BOOST_CHECK(!flt.is_open()); + BOOST_CHECK(!src.is_open()); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("auto_close test"); + test->add(BOOST_TEST_CASE(&auto_close_source)); + test->add(BOOST_TEST_CASE(&auto_close_filter)); + return test; +} diff --git a/libs/iostreams/test/bool_trait_test.cpp b/libs/iostreams/test/bool_trait_test.cpp new file mode 100644 index 0000000000..46bca21dd9 --- /dev/null +++ b/libs/iostreams/test/bool_trait_test.cpp @@ -0,0 +1,252 @@ +/* + * 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. + * + * Tests the boolean type traits defined in boost/iostreams/traits.hpp. + * + * File: libs/iostreams/test/bool_trait_test.cpp + * Date: Sun Feb 17 17:52:59 MST 2008 + * Copyright: 2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::iostreams; +namespace io = boost::iostreams; +using boost::unit_test::test_suite; + +typedef stream array_istream; +typedef stream array_wistream; +typedef stream array_ostream; +typedef stream array_wostream; +typedef stream array_stream; +typedef stream array_wstream; +typedef stream_buffer array_streambuf; +typedef stream_buffer array_wstreambuf; + +typedef io::filtering_stream filtering_iostream; +typedef io::filtering_stream filtering_wiostream; + +typedef io::detail::linked_streambuf linkedbuf; +typedef io::detail::linked_streambuf wlinkedbuf; + +#define BOOST_CHECK_BOOL_TRAIT(trait, type, status) \ + BOOST_CHECK(trait< type >::value == status) + /**/ + +#define BOOST_CHECK_STREAM_TRAIT( \ + trait, \ + istream_, wistream_, ostream_, wostream_, \ + iostream_, wiostream_, streambuf_, wstreambuf_, \ + ifstream_, wifstream_, ofstream_, wofstream_, \ + fstream_, wfstream_, filebuf_, wfilebuf_, \ + istringstream_, wistringstream_, ostringstream_, wostringstream_, \ + stringstream_, wstringstream_, stringbuf_, wstringbuf_, \ + array_istream_, array_wistream_, array_ostream_, array_wostream_, \ + array_stream_, array_wstream_, array_streambuf_, array_wstreambuf_, \ + filtering_istream_, filtering_wistream_, \ + filtering_ostream_, filtering_wostream_, \ + filtering_iostream_, filtering_wiostream_, \ + filtering_istreambuf_, filtering_wistreambuf_, \ + linkedbuf_, wlinkedbuf_ ) \ + BOOST_CHECK_BOOL_TRAIT(trait, std::istream, istream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wistream, wistream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::ostream, ostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wostream, wostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::iostream, iostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wiostream, wiostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::streambuf, streambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wstreambuf, wstreambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wifstream, wifstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::ofstream, ofstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wofstream, wofstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::fstream, fstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wfstream, wfstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::filebuf, filebuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wfilebuf, wfilebuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::istringstream, istringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wistringstream, wistringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::ostringstream, ostringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wostringstream, wostringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::stringstream, stringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wstringstream, wstringstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::stringbuf, stringbuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, std::wstringbuf, wstringbuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_istream, array_istream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_wistream, array_wistream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_ostream, array_ostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_wostream, array_wostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_stream, array_stream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_wstream, array_wstream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_streambuf, array_streambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, array_wstreambuf, array_wstreambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_istream, filtering_istream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_wistream, filtering_wistream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_ostream, filtering_ostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_wostream, filtering_wostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, filtering_iostream, filtering_iostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, filtering_wiostream, filtering_wiostream_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_istreambuf, filtering_istreambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::filtering_wistreambuf, filtering_wistreambuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, linkedbuf, linkedbuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, wlinkedbuf, wlinkedbuf_); \ + BOOST_CHECK_BOOL_TRAIT(trait, io::array, false); \ + BOOST_CHECK_BOOL_TRAIT(trait, int, false); + /**/ + +void bool_trait_test() +{ + // Test is_istream + BOOST_CHECK_STREAM_TRAIT( + io::is_istream, + true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, + false, false + ); + + // Test is_ostream + BOOST_CHECK_STREAM_TRAIT( + io::is_ostream, + false, false, true, true, true, true, false, false, + false, false, true, true, true, true, false, false, + false, false, true, true, true, true, false, false, + false, false, true, true, true, true, false, false, + false, false, true, true, true, true, false, false, + false, false + ); + + // Test is_iostream + BOOST_CHECK_STREAM_TRAIT( + io::is_iostream, + false, false, false, false, true, true, false, false, + false, false, false, false, true, true, false, false, + false, false, false, false, true, true, false, false, + false, false, false, false, true, true, false, false, + false, false, false, false, true, true, false, false, + false, false + ); + + // Test is_streambuf + BOOST_CHECK_STREAM_TRAIT( + io::is_streambuf, + false, false, false, false, false, false, true, true, + false, false, false, false, false, false, true, true, + false, false, false, false, false, false, true, true, + false, false, false, false, false, false, true, true, + false, false, false, false, false, false, true, true, + true, true + ); + + // Test is_std_io + BOOST_CHECK_STREAM_TRAIT( + io::is_std_io, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + true, true + ); + + // Test is_std_file_device + BOOST_CHECK_STREAM_TRAIT( + io::is_std_file_device, + false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, true, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false + ); + + // Test is_std_string_device + BOOST_CHECK_STREAM_TRAIT( + io::is_std_string_device, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, true, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false + ); + + // Test is_boost_stream + BOOST_CHECK_STREAM_TRAIT( + io::detail::is_boost_stream, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + true, true, true, true, true, true, false, false, + false, false, false, false, false, false, false, false, + false, false + ); + + // Test is_boost_stream_buffer + BOOST_CHECK_STREAM_TRAIT( + io::detail::is_boost_stream_buffer, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, true, true, + false, false, false, false, false, false, false, false, + false, false + ); + + // Test is_filtering_stream + BOOST_CHECK_STREAM_TRAIT( + io::detail::is_filtering_stream, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + true, true, true, true, true, true, false, false, + false, false + ); + + // Test is_filtering_streambuf + BOOST_CHECK_STREAM_TRAIT( + io::detail::is_filtering_streambuf, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, true, true, + false, false + ); + + // Test is_boost + BOOST_CHECK_STREAM_TRAIT( + io::detail::is_boost, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + false, false + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("bool trait test"); + test->add(BOOST_TEST_CASE(&bool_trait_test)); + return test; +} diff --git a/libs/iostreams/test/buffer_size_test.cpp b/libs/iostreams/test/buffer_size_test.cpp new file mode 100644 index 0000000000..83be295e1d --- /dev/null +++ b/libs/iostreams/test/buffer_size_test.cpp @@ -0,0 +1,82 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include "detail/filters.hpp" // Must come before operations.hpp for VC6. +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +struct optimally_buffered_filter { + typedef char char_type; + struct category + : input_filter_tag, + optimally_buffered_tag + { }; + std::streamsize optimal_buffer_size() const + { return default_filter_buffer_size + 1; } +}; + +void buffer_size_test() +{ + // Test device buffer sizes. + + BOOST_CHECK_MESSAGE( + optimal_buffer_size(null_source()) == default_device_buffer_size, + "wrong buffer size for sourcer" + ); + BOOST_CHECK_MESSAGE( + optimal_buffer_size(null_sink()) == default_device_buffer_size, + "wrong buffer size for sink" + ); + + // Test filter buffer sizes. + + BOOST_CHECK_MESSAGE( + optimal_buffer_size(toupper_filter()) == default_filter_buffer_size, + "wrong buffer size for input filter" + ); + BOOST_CHECK_MESSAGE( + optimal_buffer_size(tolower_filter()) == default_filter_buffer_size, + "wrong buffer size for output filter" + ); + BOOST_CHECK_MESSAGE( + optimal_buffer_size(toupper_multichar_filter()) + == + default_filter_buffer_size, + "wrong buffer size for multi-character input filter" + ); + BOOST_CHECK_MESSAGE( + optimal_buffer_size(tolower_multichar_filter()) + == + default_filter_buffer_size, + "wrong buffer size for multi-character output filter" + ); + + // Test custom buffer size. + + BOOST_CHECK_MESSAGE( + optimal_buffer_size(optimally_buffered_filter()) + == + optimally_buffered_filter().optimal_buffer_size(), + "wrong buffer size for multi-character output filter" + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("buffer_size test"); + test->add(BOOST_TEST_CASE(&buffer_size_test)); + return test; +} diff --git a/libs/iostreams/test/bzip2_test.cpp b/libs/iostreams/test/bzip2_test.cpp new file mode 100644 index 0000000000..88daa01f86 --- /dev/null +++ b/libs/iostreams/test/bzip2_test.cpp @@ -0,0 +1,96 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +struct bzip2_alloc : std::allocator { }; + +void bzip2_test() +{ + text_sequence data; + BOOST_CHECK( + test_filter_pair( bzip2_compressor(), + bzip2_decompressor(), + std::string(data.begin(), data.end()) ) + ); + BOOST_CHECK( + test_filter_pair( basic_bzip2_compressor(), + basic_bzip2_decompressor(), + std::string(data.begin(), data.end()) ) + ); + BOOST_CHECK( + test_filter_pair( bzip2_compressor(), + bzip2_decompressor(), + std::string() ) + ); + { + filtering_istream strm; + strm.push( bzip2_compressor() ); + strm.push( null_source() ); + } + { + filtering_istream strm; + strm.push( bzip2_decompressor() ); + strm.push( null_source() ); + } +} + +void multiple_member_test() +{ + text_sequence data; + std::vector temp, dest; + + // Write compressed data to temp, twice in succession + filtering_ostream out; + out.push(bzip2_compressor()); + out.push(io::back_inserter(temp)); + io::copy(make_iterator_range(data), out); + out.push(io::back_inserter(temp)); + io::copy(make_iterator_range(data), out); + + // Read compressed data from temp into dest + filtering_istream in; + in.push(bzip2_decompressor()); + in.push(array_source(&temp[0], temp.size())); + io::copy(in, io::back_inserter(dest)); + + // Check that dest consists of two copies of data + BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size()); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin())); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2)); + + dest.clear(); + io::copy( + array_source(&temp[0], temp.size()), + io::compose(bzip2_decompressor(), io::back_inserter(dest))); + + // Check that dest consists of two copies of data + BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size()); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin())); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2)); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("bzip2 test"); + test->add(BOOST_TEST_CASE(&bzip2_test)); + test->add(BOOST_TEST_CASE(&multiple_member_test)); + return test; +} diff --git a/libs/iostreams/test/close_test.cpp b/libs/iostreams/test/close_test.cpp new file mode 100644 index 0000000000..4c24057eb7 --- /dev/null +++ b/libs/iostreams/test/close_test.cpp @@ -0,0 +1,651 @@ +/* + * 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. + * + * Verifies that the close() member functions of filters and devices + * are called with the correct arguments in the correct order when + * used with chains and streams. + * + * File: libs/iostreams/test/close_test.cpp + * Date: Sun Dec 09 16:12:23 MST 2007 + * Copyright: 2007 CodeRage + * Author: Jonathan Turkanis + */ + +#include +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/operation_sequence.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +void input_chain_test() +{ + // Test input filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(2))); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test bidirectional filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test seekable filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test dual-user filter + { + operation_sequence seq; + filtering_streambuf ch; + operation dummy; + + // Test chain::pop() + ch.push( + closable_filter( + seq.new_operation(2), + dummy + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct source + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(2))); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct bidirectional device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(2))); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct seekable device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void output_chain_test() +{ + // Test output filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test bidirectional filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test seekable filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test dual-user filter + { + operation_sequence seq; + filtering_streambuf ch; + operation dummy; + + // Test chain::pop() + ch.push( + closable_filter( + dummy, + seq.new_operation(1) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct sink + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct bidirectional device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(2))); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(3) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct seekable device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void bidirectional_chain_test() +{ + // Test bidirectional filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct bidirectional device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void seekable_chain_test() +{ + // Test seekable filter and device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test direct seekable device + { + operation_sequence seq; + filtering_streambuf ch; + + // Test chain::pop() + ch.push(closable_filter(seq.new_operation(1))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.pop()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and io::close() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(io::close(ch)); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + + // Test filter reuse and chain::reset() + seq.reset(); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void stream_test() +{ + // Test source + { + operation_sequence seq; + stream< closable_device > str; + str.open(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(str.close()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test sink + { + operation_sequence seq; + stream< closable_device > str; + str.open(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(str.close()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test bidirectional device + { + operation_sequence seq; + stream< closable_device > str; + str.open( + closable_device( + seq.new_operation(1), + seq.new_operation(2) + ) + ); + BOOST_CHECK_NO_THROW(str.close()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test seekable device + { + operation_sequence seq; + stream< closable_device > str; + str.open(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(str.close()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("execute test"); + test->add(BOOST_TEST_CASE(&input_chain_test)); + test->add(BOOST_TEST_CASE(&output_chain_test)); + test->add(BOOST_TEST_CASE(&bidirectional_chain_test)); + test->add(BOOST_TEST_CASE(&seekable_chain_test)); + test->add(BOOST_TEST_CASE(&stream_test)); + return test; +} diff --git a/libs/iostreams/test/code_converter_test.cpp b/libs/iostreams/test/code_converter_test.cpp new file mode 100644 index 0000000000..35554a109c --- /dev/null +++ b/libs/iostreams/test/code_converter_test.cpp @@ -0,0 +1,387 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#ifdef BOOST_IOSTREAMS_NO_WIDE_STREAMS +# error wide streams not supported on this platform +#endif + +#include // equal. +#include +#include +#include // BOOST_DEDUCED_TYPENAME. +#include +#include +#include +#include +#include +#include +#if !defined(__COMO__) || !defined(BOOST_COMO_STRICT) +# if defined(BOOST_IOSTREAMS_NO_LIB) || defined(BOOST_ALL_NO_LIB) +# include "../src/file_descriptor.cpp" +# else +# include +# endif +#endif +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/operation_sequence.hpp" +#include "detail/temp_file.hpp" + + // Include codevct facets + +#include "detail/null_padded_codecvt.hpp" +#include "detail/utf8_codecvt_facet.hpp" +#ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif // #ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX] + +#include + +using namespace std; +using namespace boost::iostreams; +using namespace boost::iostreams::detail; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +const int max_length = 30; +const unsigned int pattern_length = 100; +const unsigned int pattern_reps = 100; + +template +bool valid_char(typename codecvt_intern::type c) +{ + typedef typename codecvt_state::type state_type; + typedef typename codecvt_intern::type intern_type; + Codecvt cvt; + state_type state = state_type(); + const intern_type* nint; + char* next; + char buf[max_length]; + + return cvt.out( state, &c, &c + 1, nint, + buf, buf + max_length, next ) + == + codecvt_base::ok; +} + +template +basic_string< + BOOST_DEDUCED_TYPENAME + codecvt_intern::type +> +test_string() +{ + typedef typename codecvt_intern::type intern_type; + std::basic_string pattern, result; + for (intern_type c = 255; pattern.size() < pattern_length; --c) + if (valid_char(c)) + pattern += c; + result.reserve(pattern.size() * pattern_reps); + for (unsigned int w = 0; w < pattern_reps; ++w) + result += pattern; + return result; +} + +// Como can't compile file_descriptor.cpp in strict mode; this failure +// is detected by file_descriptor_test.cpp. +#if !defined(__COMO__) || !defined(BOOST_COMO_STRICT) + typedef io::file_descriptor_source classic_file_source; + typedef io::file_descriptor_sink classic_file_sink; +#else + struct classic_file_source : io::source { + classic_file_source(const std::string& path) + : file_(new filebuf) + { + file_->pubimbue(locale::classic()); + file_->open(path.c_str(), BOOST_IOS::in | BOOST_IOS::binary); + } + streamsize read(char* s, streamsize n) { return file_->sgetn(s, n); } + boost::shared_ptr file_; + }; + + struct classic_file_sink : io::sink { + classic_file_sink(const std::string& path) + : file_(new filebuf) + { + file_->pubimbue(locale::classic()); + file_->open(path.c_str(), BOOST_IOS::out | BOOST_IOS::binary); + } + streamsize write(const char* s, streamsize n) { return file_->sputn(s, n); } + boost::shared_ptr file_; + }; +#endif + +template +bool codecvt_test1() +{ + typedef basic_string< + BOOST_DEDUCED_TYPENAME + codecvt_intern::type + > string_type; + typedef code_converter wide_file_source; + typedef code_converter wide_file_sink; + + BOOST_CHECK(Codecvt().max_length() <= max_length); + temp_file temp; + string_type test = test_string(); + stream out(temp.name()); + out.write(test.data(), static_cast(test.size())); + out.close(); + + stream in(temp.name()); + string_type test2; + io::copy(in, io::back_inserter(test2)); + + return test == test2; +} + +template +bool codecvt_test2() +{ + typedef basic_string< + BOOST_DEDUCED_TYPENAME + codecvt_intern::type + > string_type; + typedef code_converter wide_file_source; + typedef code_converter wide_file_sink; + + // Set global locale. + locale loc = add_facet(locale(), new Codecvt); + locale::global(loc); + + temp_file temp; + string_type test = test_string(); + stream out(temp.name()); + out.write(test.data(), static_cast(test.size())); + out.close(); + + stream in(temp.name()); + string_type test2; + io::copy(in, io::back_inserter(test2)); + + return test == test2; +} + +template +bool codecvt_test() +{ + return codecvt_test1() && codecvt_test2(); +} + +void code_converter_test() +{ + BOOST_CHECK((codecvt_test >())); + BOOST_CHECK(codecvt_test()); + BOOST_CHECK(codecvt_test()); +#ifdef BOOST_IOSTREAMS_USE_DINKUM_COREX + using namespace Dinkum::conversions; + BOOST_CHECK(codecvt_test< codecvt_8859_1 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_10 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_13 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_14 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_15 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_16 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_2 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_3 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_4 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_5 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_6 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_7 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_8 >()); + BOOST_CHECK(codecvt_test< codecvt_8859_9 >()); + BOOST_CHECK(codecvt_test< codecvt_baltic >()); + BOOST_CHECK(codecvt_test< codecvt_big5 >()); + BOOST_CHECK(codecvt_test< codecvt_cp037 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1006 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1026 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1250 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1251 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1252 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1253 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1254 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1255 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1256 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1257 >()); + BOOST_CHECK(codecvt_test< codecvt_cp1258 >()); + BOOST_CHECK(codecvt_test< codecvt_cp424 >()); + BOOST_CHECK(codecvt_test< codecvt_cp437 >()); + BOOST_CHECK(codecvt_test< codecvt_cp500 >()); + BOOST_CHECK(codecvt_test< codecvt_cp737 >()); + BOOST_CHECK(codecvt_test< codecvt_cp775 >()); + BOOST_CHECK(codecvt_test< codecvt_cp850 >()); + BOOST_CHECK(codecvt_test< codecvt_cp852 >()); + BOOST_CHECK(codecvt_test< codecvt_cp855 >()); + BOOST_CHECK(codecvt_test< codecvt_cp856 >()); + BOOST_CHECK(codecvt_test< codecvt_cp857 >()); + BOOST_CHECK(codecvt_test< codecvt_cp860 >()); + BOOST_CHECK(codecvt_test< codecvt_cp861 >()); + BOOST_CHECK(codecvt_test< codecvt_cp862 >()); + BOOST_CHECK(codecvt_test< codecvt_cp863 >()); + BOOST_CHECK(codecvt_test< codecvt_cp864 >()); + BOOST_CHECK(codecvt_test< codecvt_cp865 >()); + BOOST_CHECK(codecvt_test< codecvt_cp866 >()); + BOOST_CHECK(codecvt_test< codecvt_cp869 >()); + BOOST_CHECK(codecvt_test< codecvt_cp874 >()); + BOOST_CHECK(codecvt_test< codecvt_cp875 >()); + BOOST_CHECK(codecvt_test< codecvt_cp932 >()); + BOOST_CHECK(codecvt_test< codecvt_cp936 >()); + BOOST_CHECK(codecvt_test< codecvt_cp949 >()); + BOOST_CHECK(codecvt_test< codecvt_cp950 >()); + BOOST_CHECK(codecvt_test< codecvt_cyrillic >()); + BOOST_CHECK(codecvt_test< codecvt_ebcdic >()); + BOOST_CHECK(codecvt_test< codecvt_euc >()); + BOOST_CHECK(codecvt_test< codecvt_euc_0208 >()); + BOOST_CHECK(codecvt_test< codecvt_gb12345 >()); + BOOST_CHECK(codecvt_test< codecvt_gb2312 >()); + BOOST_CHECK(codecvt_test< codecvt_greek >()); + BOOST_CHECK(codecvt_test< codecvt_iceland >()); + BOOST_CHECK(codecvt_test< codecvt_jis >()); + BOOST_CHECK(codecvt_test< codecvt_jis_0208 >()); + BOOST_CHECK(codecvt_test< codecvt_jis0201 >()); + BOOST_CHECK(codecvt_test< codecvt_ksc5601 >()); + BOOST_CHECK(codecvt_test< codecvt_latin2 >()); + BOOST_CHECK(codecvt_test< codecvt_one_one >()); + BOOST_CHECK(codecvt_test< codecvt_roman >()); + BOOST_CHECK(codecvt_test< codecvt_sjis >()); + BOOST_CHECK(codecvt_test< codecvt_sjis_0208 >()); + BOOST_CHECK(codecvt_test< codecvt_turkish >()); + BOOST_CHECK(codecvt_test< codecvt_utf16 >()); + BOOST_CHECK(codecvt_test< codecvt_utf8 >()); + BOOST_CHECK(codecvt_test< codecvt_utf8_utf16 >()); +#endif +} + +/* Defer pending further testing +void close_test() +{ + typedef utf8_codecvt_facet codecvt_type; + + // Test code converter based on a source + { + operation_sequence seq; + io::wchain ch; + ch.push( + code_converter, codecvt_type>( + seq.new_operation(1) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test code converter based on a sink + { + operation_sequence seq; + io::wchain ch; + ch.push( + code_converter, codecvt_type>( + seq.new_operation(1) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test code converter based on a bidirectional device + { + operation_sequence seq; + io::wchain ch; + ch.push( + code_converter, codecvt_type>( + seq.new_operation(1), + 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("code_converter test"); + test->add(BOOST_TEST_CASE(&code_converter_test)); + //test->add(BOOST_TEST_CASE(&close_test)); + return test; +} diff --git a/libs/iostreams/test/combine_test.cpp b/libs/iostreams/test/combine_test.cpp new file mode 100644 index 0000000000..e22f4d59ab --- /dev/null +++ b/libs/iostreams/test/combine_test.cpp @@ -0,0 +1,227 @@ +/* + * 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. + * + * Verifies that the close() member functions of filters and devices + * are called with the correct arguments in the correct order when + * they are combined using combine(). + * + * File: libs/iostreams/test/combine_test.cpp + * Date: Sun Jan 06 01:37:37 MST 2008 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/operation_sequence.hpp" + +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +void combine_test() +{ + // Combine a source and a sink + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_device(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine two bidirectional devices + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_device( + seq.new_operation(1), + seq.new_operation(2) + ), + closable_device( + seq.new_operation(3), + seq.new_operation(4) + ) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine two seekable devices + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_device(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine an input filter and an output filter + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_filter(seq.new_operation(2)), + closable_filter(seq.new_operation(3)) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine two bidirectional filters + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ), + closable_filter( + seq.new_operation(4), + seq.new_operation(5) + ) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(6) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine two seekable filters + { + operation_sequence seq; + chain ch; + ch.push( + io::combine( + closable_filter(seq.new_operation(2)), + closable_filter(seq.new_operation(3)) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine a dual-use filter and an input filter + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::combine( + closable_filter(seq.new_operation(2)), + closable_filter( + dummy, + seq.new_operation(3) + ) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine a dual-use filter and an output filter + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::combine( + closable_filter( + seq.new_operation(2), + dummy + ), + closable_filter(seq.new_operation(3)) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Combine two dual-use filters + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::combine( + closable_filter( + seq.new_operation(2), + dummy + ), + closable_filter( + dummy, + seq.new_operation(3) + ) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ); + 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("combine test"); + test->add(BOOST_TEST_CASE(&combine_test)); + return test; +} diff --git a/libs/iostreams/test/component_access_test.cpp b/libs/iostreams/test/component_access_test.cpp new file mode 100644 index 0000000000..7298e56e2e --- /dev/null +++ b/libs/iostreams/test/component_access_test.cpp @@ -0,0 +1,173 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include // out_of_range. +#include +#include // pair. +#include // BOOST_MSVC. +#include +#include +#include +#include +#include +#include +#include +#include "detail/constants.hpp" +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +namespace io = boost::iostreams; +using boost::unit_test::test_suite; + +#define COMPARE_TYPE_ID(x, y) BOOST_IOSTREAMS_COMPARE_TYPE_ID(x, y) + +struct indirect_source : io::source { + void foo() { } + std::streamsize read(char*, std::streamsize) { return 0; } +}; + +struct direct_source { + typedef char char_type; + struct category + : io::input, io::device_tag, io::direct_tag + { }; + void foo() { } + std::pair input_sequence() + { + return std::pair(static_cast(0), static_cast(0));; + } +}; + +void compile_time_test() +{ + using namespace io; + + stream_buffer indirect_buf; + indirect_buf.open(indirect_source()); + indirect_buf->foo(); + + stream_buffer direct_buf; + direct_buf.open(direct_source()); + direct_buf->foo(); + + stream indirect_stream; + indirect_stream.open(indirect_source()); + indirect_stream->foo(); + + stream direct_stream; + direct_stream.open(direct_source()); + direct_stream->foo(); +} + +void component_type_test() +{ + using namespace std; + using namespace io; + using namespace boost::iostreams::test; + + temp_file dest; + lowercase_file lower; + + filtering_ostream out; + out.push(tolower_filter()); + out.push(tolower_multichar_filter()); + out.push(file_sink(dest.name(), out_mode)); + + // Check index 0. + BOOST_CHECK(COMPARE_TYPE_ID( + out.component_type(0), + typeid(tolower_filter) + )); + BOOST_CHECK(COMPARE_TYPE_ID( + BOOST_IOSTREAMS_COMPONENT_TYPE(out, 0), + typeid(tolower_filter) + )); + BOOST_CHECK_NO_THROW(( + BOOST_IOSTREAMS_COMPONENT(out, 0, tolower_filter) + )); +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + BOOST_CHECK_NO_THROW(( + out.component(0) + )); + BOOST_CHECK_NO_THROW(( + out.component<0, tolower_filter>() + )); +#endif + + // Check index 1. + BOOST_CHECK(COMPARE_TYPE_ID( + out.component_type(1), + typeid(tolower_multichar_filter) + )); + BOOST_CHECK(COMPARE_TYPE_ID( + BOOST_IOSTREAMS_COMPONENT_TYPE(out, 1), + typeid(tolower_multichar_filter) + )); + BOOST_CHECK_NO_THROW(( + BOOST_IOSTREAMS_COMPONENT(out, 1, tolower_multichar_filter) + )); +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + BOOST_CHECK_NO_THROW(( + out.component(1) + )); + BOOST_CHECK_NO_THROW(( + out.component<1, tolower_multichar_filter>() + )); +#endif + + // Check index 2. + BOOST_CHECK(COMPARE_TYPE_ID( + out.component_type(2), + typeid(file_sink) + )); + BOOST_CHECK(COMPARE_TYPE_ID( + BOOST_IOSTREAMS_COMPONENT_TYPE(out, 2), + typeid(file_sink) + )); + BOOST_CHECK_NO_THROW(( + BOOST_IOSTREAMS_COMPONENT(out, 2, file_sink) + )); +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + BOOST_CHECK_NO_THROW(( + out.component(2) + )); + BOOST_CHECK_NO_THROW(( + out.component<2, file_sink>() + )); +#endif + + // Check index 3. + BOOST_CHECK_THROW( + out.component_type(3), + std::out_of_range + ); + BOOST_CHECK_THROW( + BOOST_IOSTREAMS_COMPONENT_TYPE(out, 3), + std::out_of_range + ); + + // Check components. + + filtering_ostream out2; + out2.push(*(BOOST_IOSTREAMS_COMPONENT(out, 0, tolower_filter))); + out2.push(*(BOOST_IOSTREAMS_COMPONENT(out, 1, tolower_multichar_filter))); + out2.push(*(BOOST_IOSTREAMS_COMPONENT(out, 2, file_sink))); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed accessing components of chain" + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("component_type test"); + test->add(BOOST_TEST_CASE(&component_type_test)); + return test; +} diff --git a/libs/iostreams/test/compose_test.cpp b/libs/iostreams/test/compose_test.cpp new file mode 100644 index 0000000000..9d26d48a78 --- /dev/null +++ b/libs/iostreams/test/compose_test.cpp @@ -0,0 +1,504 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/operation_sequence.hpp" +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +// Must come last. +#include // BCC 5.x. + +using namespace std; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +void read_composite() +{ + test_file src1, src2; + filtering_istream first, second; + + // Test composite device + first.push(toupper_filter()); + first.push(padding_filter('a')); + first.push(file_source(src1.name(), in_mode)); + second.push( compose( toupper_filter(), + compose( padding_filter('a'), + file_source(src1.name(), in_mode) ) ) ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a stdio_filter" + ); + + // Test composite filter + first.reset(); + second.reset(); + first.push(toupper_filter()); + first.push(padding_filter('a')); + first.push(file_source(src1.name(), in_mode)); + second.push( compose( compose( toupper_filter(), + padding_filter('a') ), + file_source(src1.name(), in_mode) ) ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a stdio_filter" + ); +} + +void write_composite() +{ + temp_file dest1, dest2; + filtering_ostream out1, out2; + + // Test composite device + out1.push(tolower_filter()); + out1.push(padding_filter('a')); + out1.push(file_sink(dest1.name(), in_mode)); + out2.push( compose( tolower_filter(), + compose( padding_filter('a'), + file_sink(dest2.name(), in_mode) ) ) ); + write_data_in_chunks(out1); + write_data_in_chunks(out2); + out1.reset(); + out2.reset(); + + { + ifstream first(dest1.name().c_str()); + ifstream second(dest2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed writing to a stdio_filter" + ); + } + + // Test composite filter + out1.push(tolower_filter()); + out1.push(padding_filter('a')); + out1.push(file_sink(dest1.name(), in_mode)); + out2.push( compose( compose( tolower_filter(), + padding_filter('a') ), + file_sink(dest2.name(), in_mode) ) ); + write_data_in_chunks(out1); + write_data_in_chunks(out2); + out1.reset(); + out2.reset(); + + { + ifstream first(dest1.name().c_str()); + ifstream second(dest2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed writing to a stdio_filter" + ); + } +} + +void close_composite_device() +{ + // Compose an input filter with a source + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(2)), + closable_device(seq.new_operation(1)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a bidirectional filter with a source + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ), + closable_device(seq.new_operation(1)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a seekable filter with a source + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(2)), + closable_device(seq.new_operation(1)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a dual-use filter with a source + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + seq.new_operation(2), + dummy + ), + closable_device(seq.new_operation(1)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose an output filter with a sink + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a bidirectional filter with a sink + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(1), + seq.new_operation(2) + ), + closable_device(seq.new_operation(3)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a seekable filter with a sink + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a dual-use filter with a sink + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + dummy, + seq.new_operation(1) + ), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a bidirectional filter with a bidirectional device + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ), + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a seekable filter with a seekable device + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void close_composite_filter() +{ + // Compose two input filters + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(3)), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a bidirectional filter with an input filter + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(3), + seq.new_operation(4) + ), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_MESSAGE(seq.is_success(), seq.message()); + } + + // Compose a seekable filter with an input filter + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(3)), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a dual-use filter with an input filter + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + seq.new_operation(3), + dummy + ), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose two output filters + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a bidirectional filter with an output filter + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(1), + seq.new_operation(2) + ), + closable_filter(seq.new_operation(3)) + ) + ); + ch.push(closable_device(seq.new_operation(4))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a seekable filter with an output filter + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose a dual-use filter with an output filter + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + dummy, + seq.new_operation(1) + ), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose two bidirectional filters + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter( + seq.new_operation(3), + seq.new_operation(4) + ), + closable_filter( + seq.new_operation(2), + seq.new_operation(5) + ) + ) + ); + ch.push( + closable_device( + seq.new_operation(1), + seq.new_operation(6) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose two seekable filters + { + operation_sequence seq; + chain ch; + ch.push( + io::compose( + closable_filter(seq.new_operation(1)), + closable_filter(seq.new_operation(2)) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose two dual-use filters for input + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + seq.new_operation(3), + dummy + ), + closable_filter( + seq.new_operation(2), + dummy + ) + ) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Compose two dual-use filters for output + { + operation_sequence seq; + chain ch; + operation dummy; + ch.push( + io::compose( + closable_filter( + dummy, + seq.new_operation(1) + ), + closable_filter( + dummy, + seq.new_operation(2) + ) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + 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("line_filter test"); + test->add(BOOST_TEST_CASE(&read_composite)); + test->add(BOOST_TEST_CASE(&write_composite)); + test->add(BOOST_TEST_CASE(&close_composite_device)); + test->add(BOOST_TEST_CASE(&close_composite_filter)); + return test; +} + +#include // BCC 5.x. diff --git a/libs/iostreams/test/copy_test.cpp b/libs/iostreams/test/copy_test.cpp new file mode 100644 index 0000000000..84dda9f5db --- /dev/null +++ b/libs/iostreams/test/copy_test.cpp @@ -0,0 +1,172 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include // Equal +#include +#include // MSVC. +#include +#include // sink +#include +#include +#include +#include +#include +#include +#include "../example/container_device.hpp" +#include "detail/sequence.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::example; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +//------------------Definition of fixed_sink----------------------------------// + +/*class fixed_sink : public sink { +public: + fixed_sink(vector& storage) + : storage_(storage), pos_(0) + { } + std::streamsize write(const char_type* s, std::streamsize n) + { + streamsize capacity = static_cast(storage_.size() - pos_); + streamsize result = (min)(n, capacity); + std::copy(s, s + result, storage_.begin() + pos_); + pos_ += result; + return result; + } +private: + fixed_sink operator=(const fixed_sink&); + typedef vector::size_type size_type; + vector& storage_; + size_type pos_; +};*/ + +//------------------Definition of stream types--------------------------------// + +typedef container_source< vector > vector_source; +typedef container_sink< vector > vector_sink; +typedef stream vector_istream; +typedef stream vector_ostream; +//typedef stream fixed_ostream; + +//------------------Definition of copy_test-----------------------------------// + +void copy_test() +{ + // Stream to stream + { + test_sequence<> src; + vector dest; + vector_istream first; + vector_ostream second; + first.open(vector_source(src)); + second.open(vector_sink(dest)); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(first, second) == + static_cast(src.size()) && + src == dest, + "failed copying from stream to stream" + ); + } + + // Stream to indirect sink + { + test_sequence<> src; + vector dest; + vector_istream in; + vector_sink out(dest); + in.open(vector_source(src)); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from stream to indirect sink" + ); + } + + // Indirect source to stream + { + test_sequence<> src; + vector dest; + vector_source in(src); + vector_ostream out; + out.open(vector_sink(dest)); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from indirect source to stream" + ); + } + + // Indirect source to indirect sink + { + test_sequence<> src; + vector dest; + vector_source in(src); + vector_sink out(dest); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from indirect source to indirect sink" + ); + } + + // Direct source to direct sink + { + test_sequence<> src; + vector dest(src.size(), '?'); + array_source in(&src[0], &src[0] + src.size()); + array_sink out(&dest[0], &dest[0] + dest.size()); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from direct source to direct sink" + ); + } + + // Direct source to indirect sink + { + test_sequence<> src; + vector dest; + array_source in(&src[0], &src[0] + src.size()); + vector_ostream out(dest); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from direct source to indirect sink" + ); + } + + // Indirect source to direct sink + { + test_sequence<> src; + vector dest(src.size(), '?'); + vector_istream in; + array_sink out(&dest[0], &dest[0] + dest.size()); + in.open(vector_source(src)); + BOOST_CHECK_MESSAGE( + boost::iostreams::copy(in, out) == + static_cast(src.size()) && + src == dest, + "failed copying from indirect source to direct sink" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("copy test"); + test->add(BOOST_TEST_CASE(©_test)); + return test; +} diff --git a/libs/iostreams/test/counter_test.cpp b/libs/iostreams/test/counter_test.cpp new file mode 100644 index 0000000000..091dfe9f68 --- /dev/null +++ b/libs/iostreams/test/counter_test.cpp @@ -0,0 +1,98 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "detail/constants.hpp" +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +void read_counter() +{ + test_file src; + filtering_istream in; + in.push(counter()); + in.push(padding_filter('a'), 0); + in.push(counter()); + in.push(file_source(src.name(), in_mode)); + + counter* first_counter = BOOST_IOSTREAMS_COMPONENT(in, 0, counter); + counter* second_counter = BOOST_IOSTREAMS_COMPONENT(in, 2, counter); + int first_count = 0; + int second_count = 0; + int line_count = 0; + int reps = data_reps < 50 ? data_reps : 25; // Keep test short. + for (int w = 0; w < reps; ++w) { + int len = data_length(); + for (int z = 0; z < len; ++z) { + in.get(); + ++first_count; + ++second_count; + BOOST_CHECK(first_counter->characters() == first_count); + BOOST_CHECK(second_counter->characters() == second_count); + in.get(); + ++first_count; + BOOST_CHECK(first_counter->characters() == first_count); + BOOST_CHECK(second_counter->characters() == second_count); + } + ++line_count; + BOOST_CHECK(first_counter->lines() == line_count); + BOOST_CHECK(first_counter->lines() == line_count); + } +} + +void write_counter() +{ + filtering_ostream out; + out.push(counter()); + out.push(padding_filter('a'), 0); + out.push(counter()); + out.push(null_sink()); + + counter* first_counter = BOOST_IOSTREAMS_COMPONENT(out, 0, counter); + counter* second_counter = BOOST_IOSTREAMS_COMPONENT(out, 2, counter); + int first_count = 0; + int second_count = 0; + int line_count = 0; + int reps = data_reps < 50 ? data_reps : 25; // Keep test short. + const char* data = narrow_data(); + for (int w = 0; w < reps; ++w) { + int len = data_length(); + for (int z = 0; z < len; ++z) { + out.put(data[z]); + out.flush(); + ++first_count; + second_count += 2; + BOOST_CHECK(first_counter->characters() == first_count); + BOOST_CHECK(second_counter->characters() == second_count); + } + ++line_count; + BOOST_CHECK(first_counter->lines() == line_count); + BOOST_CHECK(first_counter->lines() == line_count); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("counter test"); + test->add(BOOST_TEST_CASE(&read_counter)); + test->add(BOOST_TEST_CASE(&write_counter)); + return test; +} diff --git a/libs/iostreams/test/deprecated_file_descriptor_test.cpp b/libs/iostreams/test/deprecated_file_descriptor_test.cpp new file mode 100644 index 0000000000..cb23f7d0e5 --- /dev/null +++ b/libs/iostreams/test/deprecated_file_descriptor_test.cpp @@ -0,0 +1,243 @@ +// (C) Copyright 2010 Daniel James +// 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.) + +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" +#include "detail/file_handle.hpp" + +// Test file_descriptor with the depreacted constructors. + +namespace boost_ios = boost::iostreams; +namespace ios_test = boost::iostreams::test; + +template +void file_handle_test_impl(FileDescriptor*) +{ + ios_test::test_file test1; + ios_test::test_file test2; + + //--------------Deprecated file descriptor constructor--------------------// + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1(handle); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + ios_test::close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1(handle, false); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + ios_test::close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1(handle, true); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1(handle); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1(handle, false); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1(handle, true); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + //--------------Deprecated file descriptor open---------------------------// + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1; + device1.open(handle); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + ios_test::close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1; + device1.open(handle, false); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + ios_test::close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + { + FileDescriptor device1; + device1.open(handle, true); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1; + device1.open(handle); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1; + device1.open(handle, false); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = ios_test::open_file_handle(test1.name()); + FileDescriptor device1; + device1.open(handle, true); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + //--------------Deprecated open with existing descriptor------------------// + + { + boost_ios::detail::file_handle handle1 = ios_test::open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = ios_test::open_file_handle(test1.name()); + + { + FileDescriptor device1(handle1); + BOOST_CHECK(device1.handle() == handle1); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.open(handle2); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.close(); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + } + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + + ios_test::close_file_handle(handle1); + } + + { + boost_ios::detail::file_handle handle1 = ios_test::open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = ios_test::open_file_handle(test1.name()); + + { + FileDescriptor device1(handle1, true); + BOOST_CHECK(device1.handle() == handle1); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.open(handle2); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.close(); + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + } + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + } + + { + boost_ios::detail::file_handle handle1 = ios_test::open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = ios_test::open_file_handle(test1.name()); + + { + FileDescriptor device1(handle1, false); + BOOST_CHECK(device1.handle() == handle1); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.open(handle2, false); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + } + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + + ios_test::close_file_handle(handle1); + ios_test::close_file_handle(handle2); + } + + { + boost_ios::detail::file_handle handle1 = ios_test::open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = ios_test::open_file_handle(test1.name()); + + { + FileDescriptor device1(handle1, true); + BOOST_CHECK(device1.handle() == handle1); + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + device1.open(handle2, true); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + } + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + } +} + +void deprecated_file_descriptor_test() +{ + file_handle_test_impl((boost_ios::file_descriptor*) 0); + file_handle_test_impl((boost_ios::file_descriptor_sink*) 0); + file_handle_test_impl((boost_ios::file_descriptor_source*) 0); +} + +boost::unit_test::test_suite* init_unit_test_suite(int, char* []) +{ + boost::unit_test::test_suite* test = BOOST_TEST_SUITE("deprecated file_descriptor test"); + test->add(BOOST_TEST_CASE(&deprecated_file_descriptor_test)); + return test; +} diff --git a/libs/iostreams/test/detail/closable.hpp b/libs/iostreams/test/detail/closable.hpp new file mode 100644 index 0000000000..182522fa51 --- /dev/null +++ b/libs/iostreams/test/detail/closable.hpp @@ -0,0 +1,343 @@ +/* + * 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. + * + * Defines a large collection of closable filters and devices that + * execute instances of boost::iostreams::test::operation upon + * closre(). Used to verify that filters and devices are closed + * correctly by the iostreams library + * + * File: libs/iostreams/test/detail/closable.hpp + * Date: Sun Dec 09 16:12:23 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#ifndef BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED + +#include +#include // EOF +#include +#include +#include "./operation_sequence.hpp" + +namespace boost { namespace iostreams { namespace test { + +template +class closable_device { }; + +// Source +template<> +class closable_device : public source { +public: + closable_device(operation close) : close_(close) { } + std::streamsize read(char*, std::streamsize) { return -1; } + void close() { close_.execute(); } +private: + operation close_; +}; + +// Sink +template<> +class closable_device : public sink { +public: + closable_device(operation close) : close_(close) { } + std::streamsize write(const char*, std::streamsize) { return 0; } + void close() { close_.execute(); } +private: + operation close_; +}; + +struct borland_output { }; + +// Copy of closable_device, for Borland <= 5.8.2 +template<> +class closable_device : public sink { +public: + closable_device(operation close) : close_(close) { } + std::streamsize write(const char*, std::streamsize) { return 0; } + void close() { close_.execute(); } +private: + operation close_; +}; + +// Bidirectional device +template<> +class closable_device : public device { +public: + closable_device(operation close_input, operation close_output) + : close_input_(close_input), close_output_(close_output) + { } + std::streamsize read(char*, std::streamsize) { return -1; } + std::streamsize write(const char*, std::streamsize) { return 0; } + void close(BOOST_IOS::openmode which) + { + switch (which) { + case BOOST_IOS::in: + close_input_.execute(); + break; + case BOOST_IOS::out: + close_output_.execute(); + break; + default: + break; + } + } +private: + operation close_input_; + operation close_output_; +}; + +// Seekable device +template<> +class closable_device : public device { +public: + closable_device(operation close) : close_(close) { } + std::streamsize read(char*, std::streamsize) { return -1; } + std::streamsize write(const char*, std::streamsize) { return 0; } + stream_offset seek(stream_offset, BOOST_IOS::seekdir) { return 0; } + void close() { close_.execute(); } +private: + operation close_; +}; + +struct direct_input + : input, device_tag, closable_tag, direct_tag + { }; +struct direct_output + : output, device_tag, closable_tag, direct_tag + { }; +struct direct_bidirectional + : bidirectional, device_tag, closable_tag, direct_tag + { }; +struct direct_seekable + : seekable, device_tag, closable_tag, direct_tag + { }; + +// Direct source +template<> +class closable_device { +public: + typedef char char_type; + typedef direct_input category; + closable_device(operation close) : close_(close) { } + std::pair input_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + void close() { close_.execute(); } +private: + operation close_; +}; + +// Direct sink +template<> +class closable_device { +public: + typedef char char_type; + typedef direct_output category; + closable_device(operation close) : close_(close) { } + std::pair output_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + void close() { close_.execute(); } +private: + operation close_; +}; + +// Direct bidirectional device +template<> +class closable_device { +public: + typedef char char_type; + typedef direct_bidirectional category; + closable_device(operation close_input, operation close_output) + : close_input_(close_input), close_output_(close_output) + { } + std::pair input_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + std::pair output_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + void close(BOOST_IOS::openmode which) + { + switch (which) { + case BOOST_IOS::in: + close_input_.execute(); + break; + case BOOST_IOS::out: + close_output_.execute(); + break; + default: + break; + } + } +private: + operation close_input_; + operation close_output_; +}; + +// Direct seekable device +template<> +class closable_device { +public: + typedef char char_type; + typedef direct_seekable category; + closable_device(operation close) : close_(close) { } + std::pair input_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + std::pair output_sequence() + { return std::pair(static_cast(0), static_cast(0)); } + void close() { close_.execute(); } +private: + operation close_; +}; + +template +class closable_filter { }; + +// Input filter +template<> +class closable_filter : public input_filter { +public: + closable_filter(operation close) : close_(close) { } + + template + int get(Source&) { return EOF; } + + template + void close(Source&) { close_.execute(); } +private: + operation close_; +}; + +// Output filter +template<> +class closable_filter : public output_filter { +public: + closable_filter(operation close) : close_(close) { } + + template + bool put(Sink&, char) { return true; } + + template + void close(Sink&) { close_.execute(); } +private: + operation close_; +}; + +// Bidirectional filter +template<> +class closable_filter : public filter { +public: + closable_filter(operation close_input, operation close_output) + : close_input_(close_input), close_output_(close_output) + { } + + template + int get(Source&) { return EOF; } + + template + bool put(Sink&, char) { return true; } + + template + void close(Device&, BOOST_IOS::openmode which) + { + switch (which) { + case BOOST_IOS::in: + close_input_.execute(); + break; + case BOOST_IOS::out: + close_output_.execute(); + break; + default: + break; + } + } +private: + operation close_input_; + operation close_output_; +}; + +// Seekable filter +template<> +class closable_filter : public filter { +public: + closable_filter(operation close) : close_(close) { } + std::streamsize read(char*, std::streamsize) { return -1; } + + template + int get(Source&) { return EOF; } + + template + bool put(Sink&, char) { return true; } + + template + stream_offset seek(Device&, stream_offset, BOOST_IOS::seekdir) + { + return 0; + } + + template + void close(Device&) { close_.execute(); } +private: + operation close_; +}; + +// Dual-use filter +template<> +class closable_filter { +public: + typedef char char_type; + struct category + : filter_tag, + dual_use, + closable_tag + { }; + closable_filter(operation close_input, operation close_output) + : close_input_(close_input), close_output_(close_output) + { } + + template + int get(Source&) { return EOF; } + + template + bool put(Sink&, char) { return true; } + + template + void close(Device&, BOOST_IOS::openmode which) + { + switch (which) { + case BOOST_IOS::in: + close_input_.execute(); + break; + case BOOST_IOS::out: + close_output_.execute(); + break; + default: + break; + } + } +private: + operation close_input_; + operation close_output_; +}; + +// Symmetric filter +class closable_symmetric_filter { +public: + typedef char char_type; + closable_symmetric_filter(operation close) : close_(close) { } + bool filter( const char*&, const char*, + char*&, char*, bool ) + { + return false; + } + void close() { close_.execute(); } +private: + operation close_; +}; + +} } } // End namespaces test, iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/constants.hpp b/libs/iostreams/test/detail/constants.hpp new file mode 100644 index 0000000000..7705d86e33 --- /dev/null +++ b/libs/iostreams/test/detail/constants.hpp @@ -0,0 +1,67 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +// Contains the definitions of several constants used by the test program. + +#ifndef BOOST_IOSTREAMS_TEST_CONSTANTS_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_CONSTANTS_HPP_INCLUDED + +#include +#include + +namespace boost { namespace iostreams { namespace test { + +// Note: openmode could be a class type, so this header must be included +// by just one TU. +const BOOST_IOS::openmode in_mode = BOOST_IOS::in | BOOST_IOS::binary; +const BOOST_IOS::openmode out_mode = BOOST_IOS::out | BOOST_IOS::binary; + +// Chunk size for reading or writing in chunks. +const int chunk_size = 59; + +// Chunk size for reading or writing in chunks. +const int small_buffer_size = 23; + +// Number of times data is repeated in test files. +const int data_reps = 300; + +namespace detail { + +// Returns string which is used to generate test files. +inline const char* data(char*) +{ + static const char* c = + "!\"#$%&'()*+,-./0123456879:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n"; + return c; +} + +// Returns string which is used to generate test files. +inline const wchar_t* data(wchar_t*) +{ + static const wchar_t* c = + L"!\"#$%&'()*+,-./0123456879:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" + L"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n"; + return c; +} + +} // End namespace detail. + +inline const char* narrow_data() { return detail::data((char*)0); } + +inline const wchar_t* wide_data() { return detail::data((wchar_t*)0); } + +// Length of string returned by data(). +inline int data_length() +{ + static int len = (int) strlen(narrow_data()); + return len; +} + +} } } // End namespaces detail, iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_CONSTANTS_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/file_handle.hpp b/libs/iostreams/test/detail/file_handle.hpp new file mode 100644 index 0000000000..a9bfed52c8 --- /dev/null +++ b/libs/iostreams/test/detail/file_handle.hpp @@ -0,0 +1,108 @@ +// (C) Copyright 2010 Daniel James +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2003-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.) + +// A few methods for getting and manipulating file handles. + +#ifndef BOOST_IOSTREAMS_FILE_HANDLE_HPP_INCLUDED +#define BOOST_IOSTREAMS_FILE_HANDLE_HPP_INCLUDED + +#include +#include +#include +#include + +#ifdef BOOST_IOSTREAMS_WINDOWS +# include // low-level file i/o. +# define WINDOWS_LEAN_AND_MEAN +# include +#else +# include +# include +#endif + +namespace boost { namespace iostreams { namespace test { + +#ifdef BOOST_IOSTREAMS_WINDOWS + +// Windows implementation + +boost::iostreams::detail::file_handle open_file_handle(std::string const& name) +{ + HANDLE handle = + ::CreateFileA( name.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); // hTemplateFile + + BOOST_REQUIRE (handle != INVALID_HANDLE_VALUE); + return handle; +} + +void close_file_handle(boost::iostreams::detail::file_handle handle) +{ + BOOST_REQUIRE(::CloseHandle(handle) == 1); +} + +#define BOOST_CHECK_HANDLE_CLOSED(handle) +#define BOOST_CHECK_HANDLE_OPEN(handle) + +#else // BOOST_IOSTREAMS_WINDOWS + +// Non-windows implementation + +boost::iostreams::detail::file_handle open_file_handle(std::string const& name) +{ + int oflag = O_RDWR; + + #ifdef _LARGEFILE64_SOURCE + oflag |= O_LARGEFILE; + #endif + + // Calculate pmode argument to open. + + mode_t pmode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH; + + // Open file. + + int fd = BOOST_IOSTREAMS_FD_OPEN(name.c_str(), oflag, pmode); + BOOST_REQUIRE (fd != -1); + + return fd; +} + +void close_file_handle(boost::iostreams::detail::file_handle handle) +{ + BOOST_REQUIRE(BOOST_IOSTREAMS_FD_CLOSE(handle) != -1); +} + +// This is pretty dubious. First you must make sure that no other +// operations that could open a descriptor are called before this +// check, otherwise it's quite likely that a closed descriptor +// could be used. Secondly, I'm not sure if it's guaranteed that +// fcntl will know that the descriptor is closed but this seems +// to work okay, and I can't see any other convenient way to check +// that a descripter has been closed. +bool is_handle_open(boost::iostreams::detail::file_handle handle) +{ + return ::fcntl(handle, F_GETFD) != -1; +} + +#define BOOST_CHECK_HANDLE_CLOSED(handle) \ + BOOST_CHECK(!::boost::iostreams::test::is_handle_open(handle)) +#define BOOST_CHECK_HANDLE_OPEN(handle) \ + BOOST_CHECK(::boost::iostreams::test::is_handle_open(handle)) + + +#endif // BOOST_IOSTREAMS_WINDOWS + +}}} + +#endif // BOOST_IOSTREAMS_FILE_HANDLE_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/filters.hpp b/libs/iostreams/test/detail/filters.hpp new file mode 100644 index 0000000000..3d01a4f8e2 --- /dev/null +++ b/libs/iostreams/test/detail/filters.hpp @@ -0,0 +1,186 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +// Contains the definitions of several constants used by the test program. + +#ifndef BOOST_IOSTREAMS_TEST_FILTERS_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_FILTERS_HPP_INCLUDED + +#include +#include // min. +#include // to_upper, to_lower. +#include // to_upper, to_lower (VC6). +#include // ptrdiff_t. +#include +#include +#include +#include +#include +#include // seekdir, streamsize. +#include +#include +#include +#include +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::toupper; using ::tolower; } +#endif + +// Must come last. +#include + +namespace boost { namespace iostreams { namespace test { + +struct toupper_filter : public input_filter { + template + int get(Source& s) + { + int c = boost::iostreams::get(s); + return c != EOF && c != WOULD_BLOCK ? + std::toupper((unsigned char) c) : + c; + } +}; +BOOST_IOSTREAMS_PIPABLE(toupper_filter, 0) + +struct tolower_filter : public output_filter { + template + bool put(Sink& s, char c) + { + return boost::iostreams::put( + s, (char) std::tolower((unsigned char) c) + ); + } +}; +BOOST_IOSTREAMS_PIPABLE(tolower_filter, 0) + +struct toupper_multichar_filter : public multichar_input_filter { + template + std::streamsize read(Source& s, char* buf, std::streamsize n) + { + std::streamsize result = boost::iostreams::read(s, buf, n); + if (result == -1) + return -1; + for (int z = 0; z < result; ++z) + buf[z] = (char) std::toupper((unsigned char) buf[z]); + return result; + } +}; +BOOST_IOSTREAMS_PIPABLE(toupper_multichar_filter, 0) + +struct tolower_multichar_filter : public multichar_output_filter { + template + std::streamsize write(Sink& s, const char* buf, std::streamsize n) + { + std::streamsize result; + for (result = 0; result < n; ++result) { + char c = (char) std::tolower((unsigned char) buf[result]); + if (!boost::iostreams::put(s, c)) + break; + } + return result; + } +}; +BOOST_IOSTREAMS_PIPABLE(tolower_multichar_filter, 0) + +struct padding_filter : dual_use_filter { + explicit padding_filter(char pad_char) + : pad_char_(pad_char), use_pad_char_(false), eof_(false) + { } + + template + int get(Source& src) + { + int result; + if (use_pad_char_) { + result = eof_ ? EOF : pad_char_; + use_pad_char_ = false; + } else { + result = boost::iostreams::get(src); + if (result != EOF && result != WOULD_BLOCK) + use_pad_char_ = true; + eof_ = result == EOF; + } + return result; + } + + template + bool put(Sink& s, char c) + { + if (use_pad_char_) { + if (!boost::iostreams::put(s, pad_char_)) + return false; + use_pad_char_ = false; + } + if (!boost::iostreams::put(s, c)) + return false; + if (!boost::iostreams::put(s, pad_char_)) + use_pad_char_ = true; + return true; + } + + char pad_char_; + bool use_pad_char_; + bool eof_; +}; +BOOST_IOSTREAMS_PIPABLE(padding_filter, 0) + +struct flushable_output_filter { + typedef char char_type; + struct category + : output_filter_tag, + flushable_tag + { }; + template + bool put(Sink&, char c) + { + buf_.push_back(c); + return true; + } + template + bool flush(Sink& s) + { + if (!buf_.empty()) { + boost::iostreams::write(s, &buf_[0], (std::streamsize) buf_.size()); + buf_.clear(); + } + return true; + } + std::vector buf_; +}; +BOOST_IOSTREAMS_PIPABLE(flushable_output_filter, 0) + +struct identity_seekable_filter : filter { + template + int get(Source& s) { return boost::iostreams::get(s); } + + template + bool put(Sink& s, char c) { return boost::iostreams::put(s, c); } + + template + std::streampos seek(Device& d, stream_offset off, BOOST_IOS::seekdir way) + { return boost::iostreams::seek(d, off, way); } +}; +BOOST_IOSTREAMS_PIPABLE(identity_seekable_filter, 0) + +struct identity_seekable_multichar_filter : multichar_filter { + template + std::streamsize read(Source& s, char* buf, std::streamsize n) + { return boost::iostreams::read(s, buf, n); } + template + std::streamsize write(Sink& s, const char* buf, std::streamsize n) + { return boost::iostreams::write(s, buf, n); } + template + std::streampos seek(Device& d, stream_offset off, BOOST_IOS::seekdir way) + { return boost::iostreams::seek(d, off, way); } +}; +BOOST_IOSTREAMS_PIPABLE(identity_seekable_multichar_filter, 0) + +} } } // End namespaces detail, iostreams, boost. + +#include + +#endif // #ifndef BOOST_IOSTREAMS_TEST_FILTERS_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/null_padded_codecvt.hpp b/libs/iostreams/test/detail/null_padded_codecvt.hpp new file mode 100644 index 0000000000..6a04e6182b --- /dev/null +++ b/libs/iostreams/test/detail/null_padded_codecvt.hpp @@ -0,0 +1,275 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +// Contains the definitions of two codecvt facets useful for testing code +// conversion. Both represent the "null padded" character encoding described as +// follows. A wide character can be represented by the encoding if its value V +// is within the range of an unsigned char. The first char of the sequence +// representing V is V % 3 + 1. This is followed by V % 3 null characters, and +// finally by V itself. + +// The first codecvt facet, null_padded_codecvt, is statefull, with state_type +// equal to int. + +// The second codecvt facet, stateless_null_padded_codecvt, is stateless. At +// each point in a conversion, no characters are consumed unless there is room +// in the output sequence to write an entire multibyte sequence. + +#ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED + +#include // NO_STDC_NAMESPACE +#include +#include +#include // mbstate_t. +#include // codecvt. +#include // const_max. + +#ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::mbstate_t; } +#endif + +namespace boost { namespace iostreams { namespace test { + +//------------------Definition of null_padded_codecvt_state-------------------// + +class null_padded_codecvt_state { +public: + null_padded_codecvt_state(int val = 0) : val_(val) { } + operator int() const { return val_; } + int& val() { return val_; } + const int& val() const { return val_; } +private: + int val_; +}; + +} } } + +BOOST_IOSTREAMS_CODECVT_SPEC(boost::iostreams::test::null_padded_codecvt_state) + +namespace boost { namespace iostreams { namespace test { + +//------------------Definition of null_padded_codevt--------------------------// + +// +// state is initially 0. After a single character is consumed, state is set to +// the number of characters in the current multibyte sequence and decremented +// as each character is consumed until its value reaches 0 again. +// +class null_padded_codecvt + : public iostreams::detail::codecvt_helper< + wchar_t, char, null_padded_codecvt_state + > +{ +public: + typedef null_padded_codecvt_state state_type; +private: + std::codecvt_base::result + do_in( state_type& state, const char* first1, const char* last1, + const char*& next1, wchar_t* first2, wchar_t* last2, + wchar_t*& next2 ) const + { + using namespace std; + if (state < 0 || state > 3) + return codecvt_base::error; + next1 = first1; + next2 = first2; + while (next2 != last2 && next1 != last1) { + while (next1 != last1) { + if (state == 0) { + if (*next1 < 1 || *next1 > 3) + return codecvt_base::error; + state = *next1++; + } else if (state == 1) { + *next2++ = (unsigned char) *next1++; + state = 0; + break; + } else { + if (*next1++ != 0) + return codecvt_base::error; + --state.val(); + } + } + } + return next2 == last2 ? + codecvt_base::ok : + codecvt_base::partial; + } + + std::codecvt_base::result + do_out( state_type& state, const wchar_t* first1, const wchar_t* last1, + const wchar_t*& next1, char* first2, char* last2, + char*& next2 ) const + { + using namespace std; + if (state < 0 || state > 3) + return codecvt_base::error; + next1 = first1; + next2 = first2; + while (next1 != last1 && next2 != last2) { + while (next2 != last2) { + if (state == 0) { + if (*next1 > integer_traits::const_max) + return codecvt_base::noconv; + state = *next1 % 3 + 1; + *next2++ = static_cast(state); + } else if (state == 1) { + state = 0; + *next2++ = static_cast(*next1++); + break; + } else { + --state.val(); + *next2++ = 0; + } + } + } + return next1 == last1 ? + codecvt_base::ok : + codecvt_base::partial; + } + + std::codecvt_base::result + do_unshift( state_type& state, + char* /* first2 */, + char* last2, + char*& next2 ) const + { + using namespace std; + next2 = last2; + while (state.val()-- > 0) + if (next2 != last2) + *next2++ = 0; + else + return codecvt_base::partial; + return codecvt_base::ok; + } + + bool do_always_noconv() const throw() { return false; } + + int do_max_length() const throw() { return 4; } + + int do_encoding() const throw() { return -1; } + + int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type& state, + const char* first1, const char* last1, + std::size_t len2 ) const throw() + { // Implementation should follow that of do_in(). + int st = state; + std::size_t result = 0; + const char* next1 = first1; + while (result < len2 && next1 != last1) { + while (next1 != last1) { + if (st == 0) { + if (*next1 < 1 || *next1 > 3) + return static_cast(result); // error. + st = *next1++; + } else if (st == 1) { + ++result; + st = 0; + break; + } else { + if (*next1++ != 0) + return static_cast(result); // error. + --st; + } + } + } + return static_cast(result); + } +}; + +//------------------Definition of stateless_null_padded_codevt----------------// + +class stateless_null_padded_codecvt + : public std::codecvt +{ + std::codecvt_base::result + do_in( state_type&, const char* first1, const char* last1, + const char*& next1, wchar_t* first2, wchar_t* last2, + wchar_t*& next2 ) const + { + using namespace std; + for ( next1 = first1, next2 = first2; + next1 != last1 && next2 != last2; ) + { + int len = (unsigned char) *next1; + if (len < 1 || len > 3) + return codecvt_base::error; + if (last1 - next1 < len + 1) + return codecvt_base::partial; + ++next1; + while (len-- > 1) + if (*next1++ != 0) + return codecvt_base::error; + *next2++ = (unsigned char) *next1++; + } + return next1 == last1 && next2 == last2 ? + codecvt_base::ok : + codecvt_base::partial; + } + + std::codecvt_base::result + do_out( state_type&, const wchar_t* first1, const wchar_t* last1, + const wchar_t*& next1, char* first2, char* last2, + char*& next2 ) const + { + using namespace std; + for ( next1 = first1, next2 = first2; + next1 != last1 && next2 != last2; ) + { + if (*next1 > integer_traits::const_max) + return codecvt_base::noconv; + int skip = *next1 % 3 + 2; + if (last2 - next2 < skip) + return codecvt_base::partial; + *next2++ = static_cast(--skip); + while (skip-- > 1) + *next2++ = 0; + *next2++ = (unsigned char) *next1++; + } + return codecvt_base::ok; + } + + std::codecvt_base::result + do_unshift( state_type&, + char* /* first2 */, + char* /* last2 */, + char*& /* next2 */ ) const + { + return std::codecvt_base::ok; + } + + bool do_always_noconv() const throw() { return false; } + + int do_max_length() const throw() { return 4; } + + int do_encoding() const throw() { return -1; } + + int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type&, + const char* first1, const char* last1, + std::size_t len2 ) const throw() + { // Implementation should follow that of do_in(). + std::size_t result = 0; + for ( const char* next1 = first1; + next1 != last1 && result < len2; ++result) + { + int len = (unsigned char) *next1; + if (len < 1 || len > 3 || last1 - next1 < len + 1) + return static_cast(result); // error. + ++next1; + while (len-- > 1) + if (*next1++ != 0) + return static_cast(result); // error. + ++next1; + } + return static_cast(result); + } +}; + +} } } // End namespaces detail, iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/operation_sequence.hpp b/libs/iostreams/test/detail/operation_sequence.hpp new file mode 100644 index 0000000000..15aaecfc74 --- /dev/null +++ b/libs/iostreams/test/detail/operation_sequence.hpp @@ -0,0 +1,224 @@ +/* + * + * 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. + * + * Defines the classes operation_sequence and operation, in the namespace + * boost::iostreams::test, for verifying that all elements of a sequence of + * operations are executed, and that they are executed in the correct order. + * + * File: libs/iostreams/test/detail/operation_sequence.hpp + * Date: Mon Dec 10 18:58:19 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED + +#include // make sure size_t is in namespace std +#include +#include +#include +#include +#include +#include // pair +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR +# define BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR 20 +#endif + +#define BOOST_CHECK_OPERATION_SEQUENCE(seq) \ + BOOST_CHECK_MESSAGE(seq.is_success(), seq.message()) \ + /**/ + +namespace boost { namespace iostreams { namespace test { + +// Simple exception class with error code built in to type +template +struct operation_error { }; + +class operation_sequence; + +// Represent an operation in a sequence of operations to be executed +class operation { +public: + friend class operation_sequence; + operation() : pimpl_() { } + void execute(); +private: + static void remove_operation(operation_sequence& seq, int id); + + struct impl { + impl(operation_sequence& seq, int id, int error_code = -1) + : seq(seq), id(id), error_code(error_code) + { } + ~impl() { remove_operation(seq, id); } + impl& operator=(const impl&); // Supress VC warning 4512 + operation_sequence& seq; + int id; + int error_code; + }; + friend struct impl; + + operation(operation_sequence& seq, int id, int error_code = -1) + : pimpl_(new impl(seq, id, error_code)) + { } + + shared_ptr pimpl_; +}; + +// Represents a sequence of operations to be executed in a particular order +class operation_sequence { +public: + friend class operation; + operation_sequence() { reset(); } + + // + // Returns a new operation. + // Parameters: + // + // id - The operation id, determining the position + // of the new operation in the operation sequence + // error_code - If supplied, indicates that the new + // operation will throw operation_error + // when executed. Must be an integer between 0 and + // BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR, + // inclusive. + // + operation new_operation(int id, int error_code = INT_MAX); + + bool is_success() const { return success_; } + bool is_failure() const { return failed_; } + std::string message() const; + void reset(); +private: + void execute(int id); + void remove_operation(int id); + operation_sequence(const operation_sequence&); + operation_sequence& operator=(const operation_sequence&); + + typedef weak_ptr ptr_type; + typedef std::map map_type; + + map_type operations_; + std::vector log_; + std::size_t total_executed_; + int last_executed_; + bool success_; + bool failed_; +}; + +//--------------Implementation of operation-----------------------------------// + +void operation::execute() +{ + pimpl_->seq.execute(pimpl_->id); + switch (pimpl_->error_code) { + + // Implementation with one or more cleanup operations + #define BOOST_PP_LOCAL_MACRO(n) \ + case n: throw operation_error(); \ + /**/ + + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR) + #include BOOST_PP_LOCAL_ITERATE() + #undef BOOST_PP_LOCAL_MACRO + + default: + break; + } +} + +inline void operation::remove_operation(operation_sequence& seq, int id) +{ + seq.remove_operation(id); +} + +//--------------Implementation of operation_sequence--------------------------// + +inline operation operation_sequence::new_operation(int id, int error_code) +{ + using namespace std; + if ( error_code < 0 || + (error_code > BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR && + error_code != INT_MAX) ) + { + throw runtime_error( string("The error code ") + + lexical_cast(error_code) + + " is out of range" ); + } + if (last_executed_ != INT_MIN) + throw runtime_error( "Operations in progress; call reset() " + "before creating more operations" ); + map_type::const_iterator it = operations_.find(id); + if (it != operations_.end()) + throw runtime_error( string("The operation ") + + lexical_cast(id) + + " already exists" ); + operation op(*this, id, error_code); + operations_.insert(make_pair(id, ptr_type(op.pimpl_))); + return op; +} + +inline std::string operation_sequence::message() const +{ + using namespace std; + if (success_) + return "success"; + std::string msg = failed_ ? + "operations occurred out of order: " : + "operation sequence is incomplete: "; + typedef vector::size_type size_type; + for (size_type z = 0, n = log_.size(); z < n; ++z) { + msg += lexical_cast(log_[z]); + if (z < n - 1) + msg += ','; + } + return msg; +} + +inline void operation_sequence::reset() +{ + log_.clear(); + total_executed_ = 0; + last_executed_ = INT_MIN; + success_ = false; + failed_ = false; +} + +inline void operation_sequence::execute(int id) +{ + log_.push_back(id); + if (!failed_ && last_executed_ < id) { + if (++total_executed_ == operations_.size()) + success_ = true; + last_executed_ = id; + } else { + success_ = false; + failed_ = true; + } +} + +inline void operation_sequence::remove_operation(int id) +{ + using namespace std; + map_type::iterator it = operations_.find(id); + if (it == operations_.end()) + throw runtime_error( string("No such operation: ") + + lexical_cast(id) ); + operations_.erase(it); +} + +} } } // End namespace boost::iostreams::test. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/sequence.hpp b/libs/iostreams/test/detail/sequence.hpp new file mode 100644 index 0000000000..0b08f7b307 --- /dev/null +++ b/libs/iostreams/test/detail/sequence.hpp @@ -0,0 +1,274 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_SEQUENCE_HPP_INCLUDED + +#include +#include +#include // strlen. +#include +#include +#include "./constants.hpp" + +namespace boost { namespace iostreams { namespace test { + +template +struct test_sequence : public std::vector { + test_sequence() + { + const Ch* buf = test::detail::data((Ch*)0); + this->reserve(data_reps * data_length()); + for (int z = 0; z < data_reps; ++z) + std::copy(buf, buf + data_length(), std::back_inserter(*this)); + } +}; + +const char* text = + "The Lord spoke to Moses saying: Speak to the children of " + "Israel, and have them take for Me an offering; from every " + "person whose heart inspires him to generosity, you shall take " + "My offering. And this is the offering that you shall take " + "from them: gold, silver, and copper; blue, purple, and " + "crimson wool; linen and goat hair; ram skins dyed red, " + "tachash skins, and acacia wood; oil for lighting, spices for " + "the anointing oil and for the incense; shoham stones and " + "filling stones for the ephod and for the choshen. And they " + "shall make Me a sanctuary and I will dwell in their midst " + "according to all that I show you, the pattern of the Mishkan " + "and the pattern of all its vessels; and so shall you do. They " + "shall make an ark of acacia wood, two and a half cubits its " + "length, a cubit and a half its width, and a cubit and a half " + "its height. And you shall overlay it with pure gold; from " + "inside and from outside you shall overlay it, and you shall " + "make upon it a golden crown all around. And you shall cast " + "four golden rings for it, and you shall place them upon its " + "four corners, two rings on its one side, and two rings on its " + "other side. And you shall make poles of acacia wood and you " + "shall overlay them with gold. And you shall bring the poles " + "into the rings on the sides of the ark, to carry the ark with " + "them. The poles of the ark shall be in the rings; they shall " + "not be removed from it. And you shall place into the ark the " + "testimony, which I will give you. " + "And you shall make an ark cover of pure gold, two and a half " + "cubits its length and a cubit and a half its width. And you " + "shall make two golden cherubim; you shall make them of " + "hammered work, from the two ends of the ark cover. And make " + "one cherub from the one end and the other cherub from the " + "other end; from the ark cover you shall make the cherubim on " + "its two ends. The cherubim shall have their wings spread " + "upwards, shielding the ark cover with their wings, with their " + "faces toward one another; [turned] toward the ark cover shall " + "be the faces of the cherubim. And you shall place the ark " + "cover on the ark from above, and into the ark you shall place " + "the testimony, which I will give you. I will arrange My " + "meetings with you there, and I will speak with you from atop " + "the ark cover from between the two cherubim that are upon the " + "Ark of the Testimony, all that I will command you unto the " + "children of Israel. And you shall make a table of acacia " + "wood, two cubits its length, one cubit its width, and a cubit " + "and a half its height. And you shall overlay it with pure " + "gold, and you shall make for it a golden crown all around. " + "And you shall make for it a frame a handbreadth [wide] all " + "around, and you shall make a golden crown for its frame all " + "around. And you shall make for it four golden rings, and you " + "shall place the rings on the four corners that are on its " + "four legs. The rings shall be opposite the frame as holders " + "for the poles [with which] to carry the table. And you shall " + "make the poles of acacia wood, and you shall overlay them " + "with gold, and the table shall be carried with them. And you " + "shall make its forms, its spoons, its half pipes, and its " + "supports with which it will be covered; of pure gold you " + "shall make them. And you shall place on the table showbread " + "before Me at all times. " + "And you shall make a menorah of pure gold. The menorah shall " + "be made of hammered work; its base and its stem, its goblets, " + "its knobs, and its flowers shall [all] be [one piece] with " + "it. And six branches coming out of its sides: three menorah " + "branches from its one side and three menorah branches from " + "its second side. Three decorated goblets on one branch, a " + "knob and a flower, and three decorated goblets on one branch, " + "a knob and a flower; so for the six branches that come out of " + "the menorah. And on [the stem of] the menorah [shall be] four " + "decorated goblets, its knobs and its flowers. And a knob under " + "the two branches from it, and a knob under the two branches " + "from it, and a knob under the two branches from it; so for the " + "six branches that come out of the menorah. Their knobs and " + "their branches shall [all] be [one piece] with it; all of it " + + "[shall be] one hammered mass of pure gold. And you shall make " + "its lamps seven, and he shall kindle its lamps [so that they] " + "shed light toward its face. And its tongs and its scoops " + "[shall be] of pure gold. He shall make it of a talent of pure " + "gold, with all these implements. Now see and make according " + "to their pattern, which you are shown on the mountain. " + "And the Mishkan you shall make out of ten curtains " + "[consisting] of twisted fine linen, and blue, purple, and " + "crimson wool. A cherubim design of the work of a master " + "weaver you shall make them. The length of one curtain [shall " + "be] twenty eight cubits, and the width of one curtain [shall " + "be] four cubits; the same measure for all the curtains. Five " + "of these curtains shall be joined to one another, and [the " + "other] five curtains shall [also] be joined to one another. " + "And you shall make loops of blue wool on the edge of one " + "curtain [that is] at the edge of the [first] set, and so " + "shall you do on the edge of the outermost curtain of the " + "second set. You shall make fifty loops on [the edge of] one " + "curtain, and you shall make fifty loops on the edge of the " + "curtain in the second set; the loops shall correspond to one " + "another. And you shall make fifty golden clasps, and you " + "shall fasten the curtains to one another with the clasps; so " + "shall the Mishkan become one. And [then] you shall make " + "curtains of goat hair for a tent over the Mishkan; you shall " + "make eleven curtains. The length of one curtain [shall be] " + "thirty cubits, and the width of one curtain four cubits; the " + "same measure for the eleven curtains. And you shall join the " + "five curtains by themselves, and the [other] six curtains by " + "themselves; and you shall fold the sixth curtain before the " + "front of the tent. And you shall make fifty loops on the edge " + "of one curtain, [which is] at the edge of the [first] set, and " + "fifty loops on the edge of the [outermost] curtain of the " + "second set. And you shall make fifty copper clasps; you shall " + "bring the clasps into the loops, and you shall fasten the " + "tent together so that it will become one. And the overhanging " + "excess in the curtains of the tent half of the extra curtain " + "shall hang over the rear of the Mishkan. And the cubit from " + "here and the cubit from there of the excess in the length of " + "the curtains of the tent shall hang over the sides of the " + "Mishkan from here and from there to cover it. And you shall " + "make a covering for the tent of ram skins dyed red and a " + "covering of tachash skins above."; + +struct text_sequence : public std::vector { + text_sequence() + { + const char* c = + "The Lord spoke to Moses saying: Speak to the children of " + "Israel, and have them take for Me an offering; from every " + "person whose heart inspires him to generosity, you shall take " + "My offering. And this is the offering that you shall take " + "from them: gold, silver, and copper; blue, purple, and " + "crimson wool; linen and goat hair; ram skins dyed red, " + "tachash skins, and acacia wood; oil for lighting, spices for " + "the anointing oil and for the incense; shoham stones and " + "filling stones for the ephod and for the choshen. And they " + "shall make Me a sanctuary and I will dwell in their midst " + "according to all that I show you, the pattern of the Mishkan " + "and the pattern of all its vessels; and so shall you do. They " + "shall make an ark of acacia wood, two and a half cubits its " + "length, a cubit and a half its width, and a cubit and a half " + "its height. And you shall overlay it with pure gold; from " + "inside and from outside you shall overlay it, and you shall " + "make upon it a golden crown all around. And you shall cast " + "four golden rings for it, and you shall place them upon its " + "four corners, two rings on its one side, and two rings on its " + "other side. And you shall make poles of acacia wood and you " + "shall overlay them with gold. And you shall bring the poles " + "into the rings on the sides of the ark, to carry the ark with " + "them. The poles of the ark shall be in the rings; they shall " + "not be removed from it. And you shall place into the ark the " + "testimony, which I will give you. " + "And you shall make an ark cover of pure gold, two and a half " + "cubits its length and a cubit and a half its width. And you " + "shall make two golden cherubim; you shall make them of " + "hammered work, from the two ends of the ark cover. And make " + "one cherub from the one end and the other cherub from the " + "other end; from the ark cover you shall make the cherubim on " + "its two ends. The cherubim shall have their wings spread " + "upwards, shielding the ark cover with their wings, with their " + "faces toward one another; [turned] toward the ark cover shall " + "be the faces of the cherubim. And you shall place the ark " + "cover on the ark from above, and into the ark you shall place " + "the testimony, which I will give you. I will arrange My " + "meetings with you there, and I will speak with you from atop " + "the ark cover from between the two cherubim that are upon the " + "Ark of the Testimony, all that I will command you unto the " + "children of Israel. And you shall make a table of acacia " + "wood, two cubits its length, one cubit its width, and a cubit " + "and a half its height. And you shall overlay it with pure " + "gold, and you shall make for it a golden crown all around. " + "And you shall make for it a frame a handbreadth [wide] all " + "around, and you shall make a golden crown for its frame all " + "around. And you shall make for it four golden rings, and you " + "shall place the rings on the four corners that are on its " + "four legs. The rings shall be opposite the frame as holders " + "for the poles [with which] to carry the table. And you shall " + "make the poles of acacia wood, and you shall overlay them " + "with gold, and the table shall be carried with them. And you " + "shall make its forms, its spoons, its half pipes, and its " + "supports with which it will be covered; of pure gold you " + "shall make them. And you shall place on the table showbread " + "before Me at all times. " + "And you shall make a menorah of pure gold. The menorah shall " + "be made of hammered work; its base and its stem, its goblets, " + "its knobs, and its flowers shall [all] be [one piece] with " + "it. And six branches coming out of its sides: three menorah " + "branches from its one side and three menorah branches from " + "its second side. Three decorated goblets on one branch, a " + "knob and a flower, and three decorated goblets on one branch, " + "a knob and a flower; so for the six branches that come out of " + "the menorah. And on [the stem of] the menorah [shall be] four " + "decorated goblets, its knobs and its flowers. And a knob under " + "the two branches from it, and a knob under the two branches " + "from it, and a knob under the two branches from it; so for the " + "six branches that come out of the menorah. Their knobs and " + "their branches shall [all] be [one piece] with it; all of it " + + "[shall be] one hammered mass of pure gold. And you shall make " + "its lamps seven, and he shall kindle its lamps [so that they] " + "shed light toward its face. And its tongs and its scoops " + "[shall be] of pure gold. He shall make it of a talent of pure " + "gold, with all these implements. Now see and make according " + "to their pattern, which you are shown on the mountain. " + "And the Mishkan you shall make out of ten curtains " + "[consisting] of twisted fine linen, and blue, purple, and " + "crimson wool. A cherubim design of the work of a master " + "weaver you shall make them. The length of one curtain [shall " + "be] twenty eight cubits, and the width of one curtain [shall " + "be] four cubits; the same measure for all the curtains. Five " + "of these curtains shall be joined to one another, and [the " + "other] five curtains shall [also] be joined to one another. " + "And you shall make loops of blue wool on the edge of one " + "curtain [that is] at the edge of the [first] set, and so " + "shall you do on the edge of the outermost curtain of the " + "second set. You shall make fifty loops on [the edge of] one " + "curtain, and you shall make fifty loops on the edge of the " + "curtain in the second set; the loops shall correspond to one " + "another. And you shall make fifty golden clasps, and you " + "shall fasten the curtains to one another with the clasps; so " + "shall the Mishkan become one. And [then] you shall make " + "curtains of goat hair for a tent over the Mishkan; you shall " + "make eleven curtains. The length of one curtain [shall be] " + "thirty cubits, and the width of one curtain four cubits; the " + "same measure for the eleven curtains. And you shall join the " + "five curtains by themselves, and the [other] six curtains by " + "themselves; and you shall fold the sixth curtain before the " + "front of the tent. And you shall make fifty loops on the edge " + "of one curtain, [which is] at the edge of the [first] set, and " + "fifty loops on the edge of the [outermost] curtain of the " + "second set. And you shall make fifty copper clasps; you shall " + "bring the clasps into the loops, and you shall fasten the " + "tent together so that it will become one. And the overhanging " + "excess in the curtains of the tent half of the extra curtain " + "shall hang over the rear of the Mishkan. And the cubit from " + "here and the cubit from there of the excess in the length of " + "the curtains of the tent shall hang over the sides of the " + "Mishkan from here and from there to cover it. And you shall " + "make a covering for the tent of ram skins dyed red and a " + "covering of tachash skins above."; + std::vector::size_type len = strlen(c); + this->reserve(len); + this->insert(this->end(), c, c + len); + } +}; + + +//----------------------------------------------------------------------------// + +} } } // End namespaces test, iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/temp_file.hpp b/libs/iostreams/test/detail/temp_file.hpp new file mode 100644 index 0000000000..51908002f5 --- /dev/null +++ b/libs/iostreams/test/detail/temp_file.hpp @@ -0,0 +1,92 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED + +#include // toupper, tolower +#include // tmpname, TMP_MAX, remove +#include // rand, toupper, tolower (VC6) +#include +#include +#include +#include "./constants.hpp" + +#ifdef BOOST_NO_STDC_NAMESPACE +# undef toupper +# undef tolower +# undef remove +# undef rand +namespace std { + using ::toupper; using ::tolower; using ::remove; using ::rand; +} +#endif + +namespace boost { namespace iostreams { namespace test { + +// Represents a temp file, deleted upon destruction. +class temp_file { +public: + + // Constructs a temp file which does not initially exist. + temp_file() { set_name(); } + ~temp_file() { std::remove(name_.c_str()); } + const ::std::string name() const { return name_; } + operator const ::std::string() const { return name_; } +private: + void set_name() { + name_ = boost::filesystem3::unique_path().string(); + } + + ::std::string name_; +}; + +struct test_file : public temp_file { + test_file() + { + BOOST_IOS::openmode mode = + BOOST_IOS::out | BOOST_IOS::binary; + ::std::ofstream f(name().c_str(), mode); + const ::std::string n(name()); + const char* buf = narrow_data(); + for (int z = 0; z < data_reps; ++z) + f.write(buf, data_length()); + } +}; + + +struct uppercase_file : public temp_file { + uppercase_file() + { + BOOST_IOS::openmode mode = + BOOST_IOS::out | BOOST_IOS::binary; + ::std::ofstream f(name().c_str(), mode); + 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])); + } +}; + +struct lowercase_file : public temp_file { + lowercase_file() + { + BOOST_IOS::openmode mode = + BOOST_IOS::out | BOOST_IOS::binary; + ::std::ofstream f(name().c_str(), mode); + 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])); + } +}; + +//----------------------------------------------------------------------------// + +} } } // End namespaces test, iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_TEST_FILES_HPP_INCLUDED diff --git a/libs/iostreams/test/detail/utf8_codecvt_facet.cpp b/libs/iostreams/test/detail/utf8_codecvt_facet.cpp new file mode 100644 index 0000000000..26679f77bf --- /dev/null +++ b/libs/iostreams/test/detail/utf8_codecvt_facet.cpp @@ -0,0 +1,371 @@ +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// utf8_codecvt_facet.cpp + +// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu) +// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu). +// Distributed under the Boost Software License, Version 1.0. (See accompany- +// ing 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. + +//#include // for multi-byte converson routines + +// Jonathan Turkanis: +// - Replaced test for BOOST_NO_STD_WSTREAMBUF with test for +// BOOST_IOSTREAMS_NO_WIDE_STREAMS; +// - Derived from codecvt_helper instead of codecvt. + +#include +#include +#ifdef BOOST_IOSTREAMS_NO_LOCALES +# error "C++ locales not supported on this platform" +#else + +#include +#include + +#include +#include "./utf8_codecvt_facet.hpp" + +#if BOOST_WORKAROUND(__BORLANDC__, <= 0x600) +# pragma warn -sig // Conversion may lose significant digits +# pragma warn -rng // Constant is out of range in comparison +#endif + +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// implementation for wchar_t + +// Translate incoming UTF-8 into UCS-4 +std::codecvt_base::result utf8_codecvt_facet_wchar_t::do_in( + std::mbstate_t&, + const char * from, + const char * from_end, + const char * & from_next, + wchar_t * to, + wchar_t * to_end, + wchar_t * & to_next +) const { + // Basic algorithm: The first octet determines how many + // octets total make up the UCS-4 character. The remaining + // "continuing octets" all begin with "10". To convert, subtract + // the amount that specifies the number of octets from the first + // octet. Subtract 0x80 (1000 0000) from each continuing octet, + // then mash the whole lot together. Note that each continuing + // octet only uses 6 bits as unique values, so only shift by + // multiples of 6 to combine. + while (from != from_end && to != to_end) { + + // Error checking on the first octet + if (invalid_leading_octet(*from)){ + from_next = from; + to_next = to; + return std::codecvt_base::error; + } + + // The first octet is adjusted by a value dependent upon + // the number of "continuing octets" encoding the character + const int cont_octet_count = get_cont_octet_count(*from); + const wchar_t octet1_modifier_table[] = { + 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc + }; + + // The unsigned char conversion is necessary in case char is + // signed (I learned this the hard way) + wchar_t ucs_result = + (unsigned char)(*from++) - octet1_modifier_table[cont_octet_count]; + + // Invariants : + // 1) At the start of the loop, 'i' continuing characters have been + // processed + // 2) *from points to the next continuing character to be processed. + int i = 0; + while(i != cont_octet_count && from != from_end) { + + // Error checking on continuing characters + if (invalid_continuing_octet(*from)) { + from_next = from; + to_next = to; + return std::codecvt_base::error; + } + + ucs_result *= (1 << 6); + + // each continuing character has an extra (10xxxxxx)b attached to + // it that must be removed. + ucs_result += (unsigned char)(*from++) - 0x80; + ++i; + } + + // If the buffer ends with an incomplete unicode character... + if (from == from_end && i != cont_octet_count) { + // rewind "from" to before the current character translation + from_next = from - (i+1); + to_next = to; + return std::codecvt_base::partial; + } + *to++ = ucs_result; + } + from_next = from; + to_next = to; + + // Were we done converting or did we run out of destination space? + if(from == from_end) return std::codecvt_base::ok; + else return std::codecvt_base::partial; +} + +std::codecvt_base::result utf8_codecvt_facet_wchar_t::do_out( + std::mbstate_t &, + const wchar_t * from, + const wchar_t * from_end, + const wchar_t * & from_next, + char * to, + char * to_end, + char * & to_next +) const +{ + // RG - consider merging this table with the other one + const wchar_t octet1_modifier_table[] = { + 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc + }; + + while (from != from_end && to != to_end) { + +#define BOOST_NULL // Prevent macro expansion + // Check for invalid UCS-4 character + if (*from > std::numeric_limits::max BOOST_NULL ()) { + from_next = from; + to_next = to; + return std::codecvt_base::error; + } +#undef BOOST_NULL + + int cont_octet_count = get_cont_octet_out_count(*from); + + // RG - comment this formula better + int shift_exponent = (cont_octet_count) * 6; + + // Process the first character + *to++ = octet1_modifier_table[cont_octet_count] + + (unsigned char)(*from / (1 << shift_exponent)); + + // Process the continuation characters + // Invariants: At the start of the loop: + // 1) 'i' continuing octets have been generated + // 2) '*to' points to the next location to place an octet + // 3) shift_exponent is 6 more than needed for the next octet + int i = 0; + while (i != cont_octet_count && to != to_end) { + shift_exponent -= 6; + *to++ = 0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)); + ++i; + } + // If we filled up the out buffer before encoding the character + if(to == to_end && i != cont_octet_count) { + from_next = from; + to_next = to - (i+1); + return std::codecvt_base::partial; + } + *from++; + } + from_next = from; + to_next = to; + // Were we done or did we run out of destination space + if(from == from_end) return std::codecvt_base::ok; + else return std::codecvt_base::partial; +} + +// How many char objects can I process to get <= max_limit +// wchar_t objects? +int utf8_codecvt_facet_wchar_t::do_length( + BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER std::mbstate_t &, + const char * from, + const char * from_end, + std::size_t max_limit +) const throw() +{ + // RG - this code is confusing! I need a better way to express it. + // and test cases. + + // Invariants: + // 1) last_octet_count has the size of the last measured character + // 2) char_count holds the number of characters shown to fit + // within the bounds so far (no greater than max_limit) + // 3) from_next points to the octet 'last_octet_count' before the + // last measured character. + int last_octet_count=0; + std::size_t char_count = 0; + const char* from_next = from; + // Use "<" because the buffer may represent incomplete characters + while (from_next+last_octet_count <= from_end && char_count <= max_limit) { + from_next += last_octet_count; + last_octet_count = (get_octet_count(*from_next)); + ++char_count; + } + return from_next-from_end; +} + +unsigned int utf8_codecvt_facet_wchar_t::get_octet_count( + unsigned char lead_octet +){ + // if the 0-bit (MSB) is 0, then 1 character + if (lead_octet <= 0x7f) return 1; + + // Otherwise the count number of consecutive 1 bits starting at MSB + assert(0xc0 <= lead_octet && lead_octet <= 0xfd); + + if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2; + else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3; + else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4; + else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5; + else return 6; +} + +namespace { +template +int get_cont_octet_out_count_impl(wchar_t word){ + if (word < 0x80) { + return 0; + } + if (word < 0x800) { + return 1; + } + return 2; +} + +// note the following code will generate on some platforms where +// wchar_t is defined as UCS2. The warnings are superfluous as +// the specialization is never instantitiated with such compilers. +template<> +int get_cont_octet_out_count_impl<4>(wchar_t word) +{ + if (word < 0x80) { + return 0; + } + if (word < 0x800) { + return 1; + } + if (word < 0x10000) { + return 2; + } + if (word < 0x200000) { + return 3; + } + if (word < 0x4000000) { + return 4; + } + return 5; +} + +} // namespace anonymous + +// How many "continuing octets" will be needed for this word +// == total octets - 1. +int utf8_codecvt_facet_wchar_t::get_cont_octet_out_count( + wchar_t word +) const { + return get_cont_octet_out_count_impl(word); +} + +#if 0 // not used? +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// implementation for char + +std::codecvt_base::result utf8_codecvt_facet_char::do_in( + std::mbstate_t & state, + const char * from, + const char * from_end, + const char * & from_next, + char * to, + char * to_end, + char * & to_next +) const +{ + while(from_next < from_end){ + wchar_t w; + wchar_t *wnext = & w; + utf8_codecvt_facet_wchar_t::result ucs4_result; + ucs4_result = base_class::do_in( + state, + from, from_end, from_next, + wnext, wnext + 1, wnext + ); + if(codecvt_base::ok != ucs4_result) + return ucs4_result; + // if the conversion succeeds. + int length = std::wctomb(to_next, w); + assert(-1 != length); + to_next += length; + } + return codecvt_base::ok; +} + +std::codecvt_base::result utf8_codecvt_facet_char::do_out( + mbstate_t & state, + const char * from, + const char * from_end, + const char * & from_next, + char * to, + char * to_end, + char * & to_next +) const +{ + while(from_next < from_end){ + wchar_t w; + int result = std::mbtowc(&w, from_next, MB_LENGTH_MAX); + assert(-1 != result); + from_next += result; + utf8_codecvt_facet_wchar_t::result ucs4_result; + + const wchar_t *wptr = & w; + ucs4_result = base_class::do_out( + state, + wptr, wptr+1, wptr, + to_next, to_end, to_next + ); + if(codecvt_base::ok != ucs4_result) + return ucs4_result; + } + return codecvt_base::ok; +} + +// How many bytes objects can I process to get <= max_limit +// char objects? +int utf8_codecvt_facet_char::do_length( + // it seems that the standard doesn't use const so these librarires + // would be in error + BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER + utf8_codecvt_facet_wchar_t::mbstate_t & initial_state, + const char * from_next, + const char * from_end, + std::size_t max_limit +) const +{ + int total_length = 0; + const char *from = from_next; + mbstate_t state = initial_state; + while(from_next < from_end){ + wchar_t w; + wchar_t *wnext = & w; + utf8_codecvt_facet_wchar_t::result ucs4_result; + ucs4_result = base_class::do_in( + state, + from_next, from_end, from_next, + wnext, wnext + 1, wnext + ); + + if(codecvt_base::ok != ucs4_result) + break; + + char carray[MB_LENGTH_MAX]; + std::size_t count = wctomb(carray, w); + if(count > max_limit) + break; + + max_limit -= count; + total_length = from_next - from; + } + return total_length; +} +#endif + +#endif //BOOST_IOSTREAMS_NO_WIDE_STREAMS diff --git a/libs/iostreams/test/detail/utf8_codecvt_facet.hpp b/libs/iostreams/test/detail/utf8_codecvt_facet.hpp new file mode 100644 index 0000000000..46932cf6eb --- /dev/null +++ b/libs/iostreams/test/detail/utf8_codecvt_facet.hpp @@ -0,0 +1,200 @@ +#ifndef BOOST_UTF8_CODECVT_FACET_HPP +#define BOOST_UTF8_CODECVT_FACET_HPP + +#include +#ifdef BOOST_IOSTREAMS_NO_WIDE_STREAMS +# error wide streams not supported on this platform +#endif + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// utf8_codecvt_facet.hpp + +// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu) +// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu). +// Distributed under the Boost Software License, Version 1.0. (See accompany- +// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note:(Robert Ramey). I have made the following alterations in the original +// code. +// a) Rendered utf8_codecvt with using templates +// b) Move longer functions outside class definition to prevent inlining +// and make code smaller +// c) added on a derived class to permit translation to/from current +// locale to utf8 + +// See http://www.boost.org for updates, documentation, and revision history. + +// archives stored as text - note these ar templated on the basic +// stream templates to accommodate wide (and other?) kind of characters +// +// note the fact that on libraries without wide characters, ostream is +// is not a specialization of basic_ostream which in fact is not defined +// in such cases. So we can't use basic_ostream but rather +// use two template parameters +// +// utf8_codecvt_facet +// This is an implementation of a std::codecvt facet for translating +// from UTF-8 externally to UCS-4. Note that this is not tied to +// any specific types in order to allow customization on platforms +// where wchar_t is not big enough. +// +// NOTES: The current implementation jumps through some unpleasant hoops in +// order to deal with signed character types. As a std::codecvt_base::result, +// it is necessary for the ExternType to be convertible to unsigned char. +// I chose not to tie the extern_type explicitly to char. But if any combination +// of types other than is used, then std::codecvt must be +// specialized on those types for this to work. + +#include +#include // size_t +#include // mbstate_t +#include +#include +#include + +// maximum lenght of a multibyte string +#define MB_LENGTH_MAX 8 + +struct utf8_codecvt_facet_wchar_t + : public boost::iostreams::detail::codecvt_helper +{ +public: + explicit utf8_codecvt_facet_wchar_t(std::size_t no_locale_manage = 0) + : boost::iostreams::detail::codecvt_helper + (no_locale_manage) + { } +protected: + virtual std::codecvt_base::result do_in( + std::mbstate_t& state, + const char * from, + const char * from_end, + const char * & from_next, + wchar_t * to, + wchar_t * to_end, + wchar_t*& to_next + ) const; + + virtual std::codecvt_base::result do_out( + std::mbstate_t & state, const wchar_t * from, + const wchar_t * from_end, const wchar_t* & from_next, + char * to, char * to_end, char * & to_next + ) const; + + bool invalid_continuing_octet(unsigned char octet_1) const { + return (octet_1 < 0x80|| 0xbf< octet_1); + } + + bool invalid_leading_octet(unsigned char octet_1) const { + return (0x7f < octet_1 && octet_1 < 0xc0) || + (octet_1 > 0xfd); + } + + // continuing octets = octets except for the leading octet + static unsigned int get_cont_octet_count(unsigned char lead_octet) { + return get_octet_count(lead_octet) - 1; + } + + static unsigned int get_octet_count(unsigned char lead_octet); + + // How many "continuing octets" will be needed for this word + // == total octets - 1. + int get_cont_octet_out_count(wchar_t word) const ; + + virtual bool do_always_noconv() const throw() { return false; } + + // UTF-8 isn't really stateful since we rewind on partial conversions + virtual std::codecvt_base::result do_unshift( + std::mbstate_t&, + char * from, + char * /* to */, + char * & next + ) const{ + next = from; + return ok; + } + + virtual int do_encoding() const throw() { + const int variable_byte_external_encoding=0; + return variable_byte_external_encoding; + } + + // How many char objects can I process to get <= max_limit + // wchar_t objects? + virtual int do_length( + BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER std::mbstate_t &, + const char * from, + const char * from_end, + std::size_t max_limit + ) const throw(); + + // Largest possible value do_length(state,from,from_end,1) could return. + virtual int do_max_length() const throw () { + return 6; // largest UTF-8 encoding of a UCS-4 character + } +}; + +#if 0 // not used - incorrect in any case +// Robert Ramey - use the above to make a code converter from multi-byte +// char strings to utf8 encoding +struct utf8_codecvt_facet_char : public utf8_codecvt_facet_wchar_t +{ + typedef utf8_codecvt_facet_wchar_t base_class; +public: + explicit utf8_codecvt_facet_char(std::size_t no_locale_manage=0) + : base_class(no_locale_manage) + {} +protected: + virtual std::codecvt_base::result do_in( + std::mbstate_t & state, + const char * from, + const char * from_end, + const char * & from_next, + char * to, + char * to_end, + char * & to_next + ) const; + + virtual std::codecvt_base::result do_out( + std::mbstate_t & state, + const char * from, + const char * from_end, + const char* & from_next, + char * to, + char * to_end, + char * & to_next + ) const; + + // How many char objects can I process to get <= max_limit + // char objects? + virtual int do_length( + const std::mbstate_t&, + const char * from, + const char * from_end, + std::size_t max_limit + ) const; +}; +#endif + +template +struct utf8_codecvt_facet +{}; + +template<> +struct utf8_codecvt_facet + : public utf8_codecvt_facet_wchar_t +{}; + +#if 0 +template<> +struct utf8_codecvt_facet + : public utf8_codecvt_facet_char +{}; +#endif + +#endif // BOOST_UTF8_CODECVT_FACET_HPP + diff --git a/libs/iostreams/test/detail/verification.hpp b/libs/iostreams/test/detail/verification.hpp new file mode 100644 index 0000000000..0ee3e31ea9 --- /dev/null +++ b/libs/iostreams/test/detail/verification.hpp @@ -0,0 +1,316 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + + +#ifndef BOOST_IOSTREAMS_TEST_VERIFICATION_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_VERIFICATION_HPP_INCLUDED + +#include +#include +#include +#include +#include +#ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES +# include +# include +#else +# include +#endif + +#include +#include +#include +#include +#include "./constants.hpp" + +// Code generation bugs cause tests to fail with global optimization. +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("g", off) +#endif + +// Included only by tests; no need to #undef. +#ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES +# define BOOST_TEMPLATE_DECL template +# define BOOST_CHAR Ch +# define BOOST_ISTREAM std::basic_istream +# define BOOST_OSTREAM std::basic_ostream +#else +# define BOOST_TEMPLATE_DECL +# define BOOST_CHAR char +# define BOOST_ISTREAM std::istream +# define BOOST_OSTREAM std::ostream +#endif + +namespace boost { namespace iostreams { namespace test { + +BOOST_TEMPLATE_DECL +bool compare_streams_in_chars(BOOST_ISTREAM& first, BOOST_ISTREAM& second) +{ + for (int z = 0; z < data_reps; ++z) + for (int w = 0; w < data_length(); ++w) + if (first.eof() != second.eof() || first.get() != second.get()) + return false; + return true; +} + +BOOST_TEMPLATE_DECL +bool compare_streams_in_chunks(BOOST_ISTREAM& first, BOOST_ISTREAM& second) +{ + int i = 0; + do { + BOOST_CHAR buf_one[chunk_size]; + BOOST_CHAR buf_two[chunk_size]; + first.read(buf_one, chunk_size); + second.read(buf_two, chunk_size); + std::streamsize amt = first.gcount(); + if ( amt != static_cast(second.gcount()) || + BOOST_IOSTREAMS_CHAR_TRAITS(BOOST_CHAR):: + compare(buf_one, buf_two, amt) != 0 ) + return false; + ++i; + } while (!first.eof()); + return true; +} + +bool compare_files(const std::string& first, const std::string& second) +{ + using namespace std; + ifstream one(first.c_str(), BOOST_IOS::in | BOOST_IOS::binary); + ifstream two(second.c_str(), BOOST_IOS::in | BOOST_IOS::binary); + return compare_streams_in_chunks(one, two); +} + +#ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES + template +#else + template +#endif +bool compare_container_and_stream(Container& cnt, BOOST_ISTREAM& is) +{ + typename Container::iterator first = cnt.begin(); + typename Container::iterator last = cnt.end(); + do { + if ((first == last) != is.eof()) return false; + if (first != last && *first++ != is.get()) return false; + } while (first != last); + return true; +} + +template +bool compare_container_and_file(Container& cnt, const std::string& file) +{ + std::ifstream fstrm(file.c_str(), BOOST_IOS::in | BOOST_IOS::binary); + return compare_container_and_stream(cnt, fstrm); +} + +BOOST_TEMPLATE_DECL +void write_data_in_chars(BOOST_OSTREAM& os) +{ + for (int z = 0; z < data_reps; ++z) + for (int w = 0; w < data_length(); ++w) + os.put(detail::data((BOOST_CHAR*)0)[w]); + os.flush(); +} + +BOOST_TEMPLATE_DECL +void write_data_in_chunks(BOOST_OSTREAM& os) +{ + const BOOST_CHAR* buf = detail::data((BOOST_CHAR*)0); + for (int z = 0; z < data_reps; ++z) + os.write(buf, data_length()); + os.flush(); +} + +bool test_seekable_in_chars(std::iostream& io) +{ + int i; // old 'for' scope workaround. + + // Test seeking with ios::cur + for (i = 0; i < data_reps; ++i) { + int j; + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(-chunk_size, BOOST_IOS::cur); + for (j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekp(-chunk_size, BOOST_IOS::cur); + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + } + + // Test seeking with ios::beg + std::streamoff off = 0; + io.seekp(0, BOOST_IOS::beg); + for (i = 0; i < data_reps; ++i, off += chunk_size) { + int j; + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(off, BOOST_IOS::beg); + for (j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekp(off, BOOST_IOS::beg); + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + } + + // Test seeking with ios::end + io.seekp(0, BOOST_IOS::end); + off = io.tellp(); + io.seekp(-off, BOOST_IOS::end); + for (i = 0; i < data_reps; ++i, off -= chunk_size) { + int j; + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(-off, BOOST_IOS::end); + for (j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekp(-off, BOOST_IOS::end); + for (j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + } + return true; +} + +bool test_seekable_in_chunks(std::iostream& io) +{ + int i; // old 'for' scope workaround. + + // Test seeking with ios::cur + for (i = 0; i < data_reps; ++i) { + io.write(narrow_data(), chunk_size); + io.seekp(-chunk_size, BOOST_IOS::cur); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + io.seekp(-chunk_size, BOOST_IOS::cur); + io.write(narrow_data(), chunk_size); + } + + // Test seeking with ios::beg + std::streamoff off = 0; + io.seekp(0, BOOST_IOS::beg); + for (i = 0; i < data_reps; ++i, off += chunk_size) { + io.write(narrow_data(), chunk_size); + io.seekp(off, BOOST_IOS::beg); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + io.seekp(off, BOOST_IOS::beg); + io.write(narrow_data(), chunk_size); + } + + // Test seeking with ios::end + io.seekp(0, BOOST_IOS::end); + off = io.tellp(); + io.seekp(-off, BOOST_IOS::end); + for (i = 0; i < data_reps; ++i, off -= chunk_size) { + io.write(narrow_data(), chunk_size); + io.seekp(-off, BOOST_IOS::end); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + io.seekp(-off, BOOST_IOS::end); + io.write(narrow_data(), chunk_size); + } + return true; +} + +bool test_input_seekable(std::istream& io) +{ + int i; // old 'for' scope workaround. + + // Test seeking with ios::cur + for (i = 0; i < data_reps; ++i) { + for (int j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekg(-chunk_size, BOOST_IOS::cur); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + } + + // Test seeking with ios::beg + std::streamoff off = 0; + io.seekg(0, BOOST_IOS::beg); + for (i = 0; i < data_reps; ++i, off += chunk_size) { + for (int j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekg(off, BOOST_IOS::beg); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + } + + // Test seeking with ios::end + io.seekg(0, BOOST_IOS::end); + off = io.tellg(); + io.seekg(-off, BOOST_IOS::end); + for (i = 0; i < data_reps; ++i, off -= chunk_size) { + for (int j = 0; j < chunk_size; ++j) + if (io.get() != narrow_data()[j]) + return false; + io.seekg(-off, BOOST_IOS::end); + char buf[chunk_size]; + io.read(buf, chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + } + return true; +} + +bool test_output_seekable(std::ostream& io) +{ + int i; // old 'for' scope workaround. + + // Test seeking with ios::cur + for (i = 0; i < data_reps; ++i) { + for (int j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(-chunk_size, BOOST_IOS::cur); + io.write(narrow_data(), chunk_size); + } + + // Test seeking with ios::beg + std::streamoff off = 0; + io.seekp(0, BOOST_IOS::beg); + for (i = 0; i < data_reps; ++i, off += chunk_size) { + for (int j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(off, BOOST_IOS::beg); + io.write(narrow_data(), chunk_size); + } + + // Test seeking with ios::end + io.seekp(0, BOOST_IOS::end); + off = io.tellp(); + io.seekp(-off, BOOST_IOS::end); + for (i = 0; i < data_reps; ++i, off -= chunk_size) { + for (int j = 0; j < chunk_size; ++j) + io.put(narrow_data()[j]); + io.seekp(-off, BOOST_IOS::end); + io.write(narrow_data(), chunk_size); + } + return true; +} + +} } } // End namespaces test, iostreams, boost. + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("", on) +#endif + +#endif // #ifndef BOOST_IOSTREAMS_TEST_VERIFICATION_HPP_INCLUDED diff --git a/libs/iostreams/test/direct_adapter_test.cpp b/libs/iostreams/test/direct_adapter_test.cpp new file mode 100644 index 0000000000..0be50b0868 --- /dev/null +++ b/libs/iostreams/test/direct_adapter_test.cpp @@ -0,0 +1,111 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include // equal. +#include +#include +#include +#include +#include +#include +#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; + +void direct_adapter_test() +{ + + typedef boost::iostreams::detail::direct_adapter + indirect_array_source; + typedef boost::iostreams::detail::direct_adapter + indirect_array_sink; + typedef boost::iostreams::detail::direct_adapter + indirect_array; + typedef stream + indirect_array_istream; + typedef stream + indirect_array_ostream; + typedef stream + indirect_array_stream; + + test_file test; + test_sequence<> seq; + + //--------------indirect_array_istream------------------------------------// + + { + indirect_array_istream first(&seq[0], &seq[0] + seq.size()); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from indirect_array_istream in chars" + ); + } + + { + indirect_array_istream first(&seq[0], &seq[0] + seq.size()); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from indirect_array_istream in chunks" + ); + } + + //--------------indirect_array_ostream------------------------------------// + + { + vector dest(data_reps * data_length(), '?'); + indirect_array_ostream out(&dest[0], &dest[0] + dest.size()); + write_data_in_chars(out); + BOOST_CHECK_MESSAGE( + std::equal(seq.begin(), seq.end(), dest.begin()), + "failed writing to indirect_array_ostream in chunks" + ); + } + + { + vector dest(data_reps * data_length(), '?'); + indirect_array_ostream out(&dest[0], &dest[0] + dest.size()); + write_data_in_chunks(out); + BOOST_CHECK_MESSAGE( + std::equal(seq.begin(), seq.end(), dest.begin()), + "failed writing to indirect_array_ostream in chunks" + ); + } + + //--------------indirect_array_stream-------------------------------------// + + { + vector test(data_reps * data_length(), '?'); + indirect_array_stream io(&test[0], &test[0] + test.size()); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within indirect_array_stream, in chars" + ); + } + + { + vector test(data_reps * data_length(), '?'); + indirect_array_stream io(&test[0], &test[0] + test.size()); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within indirect_array_stream, in chunks" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("direct_adapter test"); + test->add(BOOST_TEST_CASE(&direct_adapter_test)); + return test; +} diff --git a/libs/iostreams/test/example_test.cpp b/libs/iostreams/test/example_test.cpp new file mode 100644 index 0000000000..24384422a4 --- /dev/null +++ b/libs/iostreams/test/example_test.cpp @@ -0,0 +1,461 @@ +// (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. + +#include +#include // failure. +#include +#include +#include +#include +#include +#include +#include "../example/container_device.hpp" +#include "../example/dictionary_filter.hpp" +#include "../example/line_wrapping_filter.hpp" +#include "../example/shell_comments_filter.hpp" +#include "../example/tab_expanding_filter.hpp" +#include "../example/unix2dos_filter.hpp" +#include "./detail/verification.hpp" +#include "./detail/sequence.hpp" +#include "./detail/temp_file.hpp" + +using boost::unit_test::test_suite; +namespace io = boost::iostreams; +namespace ex = boost::iostreams::example; + +//------------------container_device test-------------------------------------// + +void container_device_test() +{ + using namespace std; + using namespace boost::iostreams::test; + + typedef vector vector_type; + typedef ex::container_source vector_source; + typedef ex::container_sink vector_sink; + typedef ex::container_device vector_device; + + { + test_sequence<> seq; + test_file file; + io::stream first(seq); + io::stream second(file.name(), in_mode); + BOOST_CHECK(compare_streams_in_chunks(first, second)); + } + + { + std::vector first; + test_sequence<> second; + io::stream out(first); + write_data_in_chunks(out); + BOOST_CHECK(first == second); + } + + { + vector v; + io::stream io(v); + BOOST_CHECK(test_seekable_in_chunks(io)); + } +} + +//------------------dictionary_filter test------------------------------------// + +void dictionary_filter_test() +{ + using namespace std; + + io::example::dictionary d; + + // See http://english2american.com. + d.add("answerphone", "answering machine"); + d.add("bloke", "guy"); + d.add("gearbox", "transmission"); + d.add("ironmonger", "hardware shop"); + d.add("loo", "restroom"); + d.add("lorry", "truck"); + d.add("rubber", "eraser"); + d.add("spanner", "monkey wrench"); + d.add("telly", "TV"); + d.add("tyre", "tire"); + d.add("waistcoat", "vest"); + d.add("windscreen", "windshield"); + + const std::string input = // Note: last character is non-alphabetic. + "I had a message on my answerphone from the bloke at the car " + "dealership that the windscreen and tyre on my lorry were replaced. " + "However, the gearbox would not be ready until tomorrow since the " + "spanner that they needed was broken and they had to go to the " + "ironmonger to buy a replacement. Since my lorry was not ready, " + "I decided to take the bus downtown and buy a new waistcoat. I " + "also stopped at the liquor store to buy some wine. I came home " + "and watched the telly and drank my wine. I also worked on a " + "crossword puzzle. Fortunately I had a pencil with a new rubber. " + "During that evening I made frequent trips to the loo due to my " + "excessive drinking"; + + const std::string output = // Note: last character is non-alphabetic. + "I had a message on my answering machine from the guy at the car " + "dealership that the windshield and tire on my truck were replaced. " + "However, the transmission would not be ready until tomorrow since " + "the monkey wrench that they needed was broken and they had to go to " + "the hardware shop to buy a replacement. Since my truck was not ready, " + "I decided to take the bus downtown and buy a new vest. I also stopped " + "at the liquor store to buy some wine. I came home and watched the TV " + "and drank my wine. I also worked on a crossword puzzle. Fortunately I " + "had a pencil with a new eraser. During that evening I made frequent " + "trips to the restroom due to my excessive drinking"; + + BOOST_CHECK( + io::test_input_filter( io::example::dictionary_stdio_filter(d), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::dictionary_stdio_filter(d), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::dictionary_input_filter(d), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::dictionary_output_filter(d), + input, output ) + ); +} + +//------------------line_wrapping_filter test---------------------------------// + +void line_wrapping_filter_test() +{ + using namespace std; + + const std::string input = + "I had a message on my answerphone from the bloke at the car \n" + "dealership that the windscreen and tyre on my lorry were replaced. \n" + "However, the gearbox would not be ready until tomorrow since the \n" + "spanner that they needed was broken and they had to go to the \n" + "ironmonger to buy a replacement. Since my lorry was not ready, \n" + "I decided to take the bus downtown and buy a new waistcoat. I \n" + "also stopped at the liquor store to buy some wine. I came home \n" + "and watched the telly and drank my wine. I also worked on a \n" + "crossword puzzle. Fortunately I had a pencil with a new rubber. \n" + "During that evening I made frequent trips to the loo due to my \n" + "excessive drinking."; + + const std::string output = + "I had a message on my answerphone from t\n" + "he bloke at the car \n" + "dealership that the windscreen and tyre \n" + "on my lorry were replaced. \n" + "However, the gearbox would not be ready \n" + "until tomorrow since the \n" + "spanner that they needed was broken and \n" + "they had to go to the \n" + "ironmonger to buy a replacement. Since m\n" + "y lorry was not ready, \n" + "I decided to take the bus downtown and b\n" + "uy a new waistcoat. I \n" + "also stopped at the liquor store to buy \n" + "some wine. I came home \n" + "and watched the telly and drank my wine.\n" + " I also worked on a \n" + "crossword puzzle. Fortunately I had a pe\n" + "ncil with a new rubber. \n" + "During that evening I made frequent trip\n" + "s to the loo due to my \n" + "excessive drinking."; + + BOOST_CHECK( + io::test_input_filter( io::example::line_wrapping_stdio_filter(40), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::line_wrapping_stdio_filter(40), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::line_wrapping_input_filter(40), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::line_wrapping_output_filter(40), + input, output ) + ); +} + +//------------------shell_comments_filter test--------------------------------// + +void shell_comments_filter_test() +{ + using namespace std; + + const std::string input = // From . + "lib boost_filesystem\n" + " : ../src/$(SOURCES).cpp\n" + " : # build requirements\n" + " [ common-names ] # magic for install and auto-link features\n" + " $(BOOST_ROOT) $(BOOST_ROOT)\n" + " exception.cpp operations_posix_windows.cpp\n" + " : debug release # build variants\n" + " ;\n" + "\n" + "dll boost_filesystem\n" + " : ../src/$(SOURCES).cpp\n" + " : # build requirements\n" + " [ common-names ] # magic for install and auto-link features\n" + " BOOST_FILESYSTEM_DYN_LINK=1 # tell source we're building dll's\n" + " dynamic # build only for dynamic runtimes\n" + " $(BOOST_ROOT) $(BOOST_ROOT)\n" + " exception.cpp operations_posix_windows.cpp\n" + " : debug release # build variants\n" + " ;"; + + const std::string output = + "lib boost_filesystem\n" + " : ../src/$(SOURCES).cpp\n" + " : \n" + " [ common-names ] \n" + " $(BOOST_ROOT) $(BOOST_ROOT)\n" + " exception.cpp operations_posix_windows.cpp\n" + " : debug release \n" + " ;\n" + "\n" + "dll boost_filesystem\n" + " : ../src/$(SOURCES).cpp\n" + " : \n" + " [ common-names ] \n" + " BOOST_FILESYSTEM_DYN_LINK=1 \n" + " dynamic \n" + " $(BOOST_ROOT) $(BOOST_ROOT)\n" + " exception.cpp operations_posix_windows.cpp\n" + " : debug release \n" + " ;"; + + BOOST_CHECK( + io::test_input_filter( io::example::shell_comments_stdio_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::shell_comments_stdio_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::shell_comments_input_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::shell_comments_output_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::shell_comments_dual_use_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::shell_comments_dual_use_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::shell_comments_multichar_input_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::shell_comments_multichar_output_filter(), + input, output ) + ); +} + +//------------------tab_expanding_filter test---------------------------------// + +void tab_expanding_filter_test() +{ + using namespace std; + + const std::string input = + "class tab_expanding_stdio_filter : public stdio_filter {\n" + "public:\n" + "\texplicit tab_expanding_stdio_filter(int\ttab_size = 8)\n" + "\t\t: tab_size_(tab_size), col_no_(0)\n" + "\t{\n" + "\t\tassert(tab_size\t> 0);\n" + "\t}\n" + "private:\n" + "\tvoid do_filter()\n" + "\t{\n" + "\t\tint\tc;\n" + "\t\twhile ((c = std::cin.get()) != EOF) {\n" + "\t\t\tif (c == '\\t') {\n" + "\t\t\t\tint\tspaces = tab_size_ - (col_no_ %\ttab_size_);\n" + "\t\t\t\tfor\t(; spaces >\t0; --spaces)\n" + "\t\t\t\t\tput_char(' ');\n" + "\t\t\t} else {\n" + "\t\t\t\tput_char(c);\n" + "\t\t\t}\n" + "\t\t}\n" + "\t}\n" + "\tvoid do_close()\t{ col_no_ =\t0; }\n" + "\tvoid put_char(int c)\n" + "\t{\n" + "\t\tstd::cout.put(c);\n" + "\t\tif (c == '\\n') {\n" + "\t\t\tcol_no_\t= 0;\n" + "\t\t} else {\n" + "\t\t\t++col_no_;\n" + "\t\t}\n" + "\t}\n" + "\tint\t tab_size_;\n" + "\tint\t col_no_;\n" + "};"; + + const std::string output = + "class tab_expanding_stdio_filter : public stdio_filter {\n" + "public:\n" + " explicit tab_expanding_stdio_filter(int tab_size = 8)\n" + " : tab_size_(tab_size), col_no_(0)\n" + " {\n" + " assert(tab_size > 0);\n" + " }\n" + "private:\n" + " void do_filter()\n" + " {\n" + " int c;\n" + " while ((c = std::cin.get()) != EOF) {\n" + " if (c == '\\t') {\n" + " int spaces = tab_size_ - (col_no_ % tab_size_);\n" + " for (; spaces > 0; --spaces)\n" + " put_char(' ');\n" + " } else {\n" + " put_char(c);\n" + " }\n" + " }\n" + " }\n" + " void do_close() { col_no_ = 0; }\n" + " void put_char(int c)\n" + " {\n" + " std::cout.put(c);\n" + " if (c == '\\n') {\n" + " col_no_ = 0;\n" + " } else {\n" + " ++col_no_;\n" + " }\n" + " }\n" + " int tab_size_;\n" + " int col_no_;\n" + "};"; + + BOOST_CHECK( + io::test_input_filter( io::example::tab_expanding_stdio_filter(4), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::tab_expanding_stdio_filter(4), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::tab_expanding_input_filter(4), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::tab_expanding_output_filter(4), + input, output ) + ); +} + +//------------------unix2dos_filter test--------------------------------------// + +void unix2dos_filter_test() +{ + using namespace std; + + const std::string input = + "When I was one-and-twenty\n" + "I heard a wise man say,\n" + "'Give crowns and pounds and guineas\n" + "But not your heart away;\n" + "\n" + "Give pearls away and rubies\n" + "But keep your fancy free.'\n" + "But I was one-and-twenty,\n" + "No use to talk to me.\n" + "\n" + "When I was one-and-twenty\n" + "I heard him say again,\n" + "'The heart out of the bosom\n" + "Was never given in vain;\n" + "'Tis paid with sighs a plenty\n" + "And sold for endless rue.'\n" + "And I am two-and-twenty,\n" + "And oh, 'tis true, 'tis true."; + + const std::string output = + "When I was one-and-twenty\r\n" + "I heard a wise man say,\r\n" + "'Give crowns and pounds and guineas\r\n" + "But not your heart away;\r\n" + "\r\n" + "Give pearls away and rubies\r\n" + "But keep your fancy free.'\r\n" + "But I was one-and-twenty,\r\n" + "No use to talk to me.\r\n" + "\r\n" + "When I was one-and-twenty\r\n" + "I heard him say again,\r\n" + "'The heart out of the bosom\r\n" + "Was never given in vain;\r\n" + "'Tis paid with sighs a plenty\r\n" + "And sold for endless rue.'\r\n" + "And I am two-and-twenty,\r\n" + "And oh, 'tis true, 'tis true."; + + BOOST_CHECK( + io::test_input_filter( io::example::unix2dos_stdio_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::unix2dos_stdio_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_input_filter( io::example::unix2dos_input_filter(), + input, output ) + ); + + BOOST_CHECK( + io::test_output_filter( io::example::unix2dos_output_filter(), + input, output ) + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("example test"); + test->add(BOOST_TEST_CASE(&container_device_test)); + test->add(BOOST_TEST_CASE(&dictionary_filter_test)); + test->add(BOOST_TEST_CASE(&tab_expanding_filter_test)); + test->add(BOOST_TEST_CASE(&line_wrapping_filter_test)); + test->add(BOOST_TEST_CASE(&shell_comments_filter_test)); + test->add(BOOST_TEST_CASE(&unix2dos_filter_test)); + return test; +} diff --git a/libs/iostreams/test/execute_test.cpp b/libs/iostreams/test/execute_test.cpp new file mode 100644 index 0000000000..d477c6792d --- /dev/null +++ b/libs/iostreams/test/execute_test.cpp @@ -0,0 +1,660 @@ +/* + * 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. + * + * Tests the function templates boost::iostreams::detail::execute_all and + * boost::iostreams::detail::execute_foreach + * + * File: libs/iostreams/test/execute_test.cpp + * Date: Thu Dec 06 13:21:54 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::detail; +using boost::unit_test::test_suite; + +// Function object that sets a boolean flag and returns a value +// specified at construction +template +class operation { +public: + typedef Result result_type; + explicit operation(Result r, bool& executed) + : r_(r), executed_(executed) + { } + Result operator()() const + { + executed_ = true; + return r_; + } +private: + operation& operator=(const operation&); + Result r_; + bool& executed_; +}; + +// Specialization for void return +template<> +class operation { +public: + typedef void result_type; + explicit operation(bool& executed) : executed_(executed) { } + void operator()() const { executed_ = true; } +private: + operation& operator=(const operation&); + bool& executed_; +}; + +// Simple exception class with error code built in to type +template +struct error { }; + +// Function object that sets a boolean flag and throws an exception +template +class thrower { +public: + typedef void result_type; + explicit thrower(bool& executed) : executed_(executed) { } + void operator()() const + { + executed_ = true; + throw error(); + } +private: + thrower& operator=(const thrower&); + bool& executed_; +}; + +// Function object for use by foreach_test +class foreach_func { +public: + typedef void result_type; + explicit foreach_func(int& count) : count_(count) { } + void operator()(int x) const + { + ++count_; + switch (x) { + case 0: throw error<0>(); + case 1: throw error<1>(); + case 2: throw error<2>(); + case 3: throw error<3>(); + case 4: throw error<4>(); + case 5: throw error<5>(); + case 6: throw error<6>(); + case 7: throw error<7>(); + case 8: throw error<8>(); + case 9: throw error<9>(); + default: + break; + } + } +private: + foreach_func& operator=(const foreach_func&); + int& count_; // Number of times operator() has been called +}; + +void success_test() +{ + // Test returning an int + { + bool executed = false; + BOOST_CHECK(execute_all(operation(9, executed)) == 9); + BOOST_CHECK(executed); + } + + // Test returning void + { + bool executed = false; + execute_all(operation(executed)); + BOOST_CHECK(executed); + } + + // Test returning an int with one cleanup operation + { + bool executed = false, cleaned_up = false; + BOOST_CHECK( + execute_all( + operation(9, executed), + operation(cleaned_up) + ) == 9 + ); + BOOST_CHECK(executed && cleaned_up); + } + + // Test returning void with one cleanup operation + { + bool executed = false, cleaned_up = false; + execute_all( + operation(executed), + operation(cleaned_up) + ); + BOOST_CHECK(executed && cleaned_up); + } + + // Test returning an int with two cleanup operations + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK( + execute_all( + operation(9, executed), + operation(cleaned_up1), + operation(cleaned_up2) + ) == 9 + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test returning void with two cleanup operations + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + execute_all( + operation(executed), + operation(cleaned_up1), + operation(cleaned_up2) + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test returning an int with three cleanup operations + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK( + execute_all( + operation(9, executed), + operation(cleaned_up1), + operation(cleaned_up2), + operation(cleaned_up3) + ) == 9 + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test returning void with three cleanup operations + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + execute_all( + operation(executed), + operation(cleaned_up1), + operation(cleaned_up2), + operation(cleaned_up3) + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } +} + +void operation_throws_test() +{ + // Test primary operation throwing with no cleanup operations + { + bool executed = false; + BOOST_CHECK_THROW( + execute_all(thrower<0>(executed)), + error<0> + ); + BOOST_CHECK(executed); + } + + // Test primary operation throwing with one cleanup operation + { + bool executed = false, cleaned_up = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up); + } + + // Test primary operation throwing with two cleanup operations + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up1), + operation(cleaned_up2) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test primary operation throwing with three cleanup operations + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up1), + operation(cleaned_up2), + operation(cleaned_up3) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } +} + +void cleanup_throws_test() +{ + // Test single cleanup operation that throws + { + bool executed = false, cleaned_up = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up); + } + + // Test fist of two cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + operation(cleaned_up2) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test second of two cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + operation(cleaned_up1), + thrower<2>(cleaned_up2) + ), + error<2> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test first of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + operation(cleaned_up2), + operation(cleaned_up3) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test second of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + operation(cleaned_up1), + thrower<2>(cleaned_up2), + operation(cleaned_up3) + ), + error<2> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test third of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + operation(cleaned_up1), + operation(cleaned_up2), + thrower<3>(cleaned_up3) + ), + error<3> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } +} + +void multiple_exceptions_test() +{ + // Test primary operation and cleanup operation throwing + { + bool executed = false, cleaned_up = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + thrower<1>(cleaned_up) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up); + } + + // Test primary operation and first of two cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + thrower<1>(cleaned_up1), + operation(cleaned_up2) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test primary operation and second of two cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up1), + thrower<2>(cleaned_up2) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test two cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, cleaned_up2 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + thrower<2>(cleaned_up2) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); + } + + // Test primary operation and first of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + thrower<1>(cleaned_up1), + operation(cleaned_up2), + operation(cleaned_up3) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test primary operation and second of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up1), + thrower<2>(cleaned_up2), + operation(cleaned_up3) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test primary operation and third of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + thrower<0>(executed), + operation(cleaned_up1), + operation(cleaned_up2), + thrower<3>(cleaned_up3) + ), + error<0> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test first and second of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + thrower<2>(cleaned_up2), + operation(cleaned_up3) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test first and third of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + operation(cleaned_up2), + thrower<3>(cleaned_up3) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test second and third of three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + operation(cleaned_up1), + thrower<2>(cleaned_up2), + thrower<3>(cleaned_up3) + ), + error<2> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } + + // Test three cleanup operations throwing + { + bool executed = false, cleaned_up1 = false, + cleaned_up2 = false, cleaned_up3 = false; + BOOST_CHECK_THROW( + execute_all( + operation(executed), + thrower<1>(cleaned_up1), + thrower<2>(cleaned_up2), + thrower<3>(cleaned_up3) + ), + error<1> + ); + BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); + } +} + +#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])) + +void foreach_test() +{ + // Test case where neither of two operations throws + { + int count = 0; + int seq[] = {-1, -1}; + BOOST_CHECK_NO_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)) + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where first of two operations throws + { + int count = 0; + int seq[] = {0, -1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where second of two operations throws + { + int count = 0; + int seq[] = {-1, 1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<1> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where both of two operations throw + { + int count = 0; + int seq[] = {0, 1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where none of three operations throws + { + int count = 0; + int seq[] = {-1, -1, -1}; + BOOST_CHECK_NO_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)) + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where first of three operations throw + { + int count = 0; + int seq[] = {0, -1, -1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where second of three operations throw + { + int count = 0; + int seq[] = {-1, 1, -1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<1> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where third of three operations throw + { + int count = 0; + int seq[] = {-1, -1, 2}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<2> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where first and second of three operations throw + { + int count = 0; + int seq[] = {0, 1, -1}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where first and third of three operations throw + { + int count = 0; + int seq[] = {0, -1, 2}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where second and third of three operations throw + { + int count = 0; + int seq[] = {-1, 1, 2}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<1> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } + + // Test case where three of three operations throw + { + int count = 0; + int seq[] = {0, 1, 2}; + BOOST_CHECK_THROW( + execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), + error<0> + ); + BOOST_CHECK(count == ARRAY_SIZE(seq)); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("execute test"); + test->add(BOOST_TEST_CASE(&success_test)); + test->add(BOOST_TEST_CASE(&operation_throws_test)); + test->add(BOOST_TEST_CASE(&cleanup_throws_test)); + test->add(BOOST_TEST_CASE(&multiple_exceptions_test)); + test->add(BOOST_TEST_CASE(&foreach_test)); + return test; +} diff --git a/libs/iostreams/test/file_descriptor_test.cpp b/libs/iostreams/test/file_descriptor_test.cpp new file mode 100644 index 0000000000..2260f4f9f0 --- /dev/null +++ b/libs/iostreams/test/file_descriptor_test.cpp @@ -0,0 +1,642 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" +#include "detail/file_handle.hpp" + +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +namespace boost_ios = boost::iostreams; +using std::ifstream; +using boost::unit_test::test_suite; + +void file_descriptor_test() +{ + + typedef stream fdistream; + typedef stream fdostream; + typedef stream fdstream; + + test_file test1; + test_file test2; + + //--------------Test file_descriptor_source-------------------------------// + + { + fdistream first(file_descriptor_source(test1.name()), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from file_descriptor_source in chars with no buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + fdistream first(file_descriptor_source(test1.name()), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from file_descriptor_source in chunks with no buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + file_descriptor_source file(test1.name()); + fdistream first(file); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from file_descriptor_source in chars with buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + file_descriptor_source file(test1.name()); + fdistream first(file); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from file_descriptor_source in chunks with buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + // test illegal flag combinations + { + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::app | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::out), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::out | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::out | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_source(test1.name(), + BOOST_IOS::out | BOOST_IOS::app | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + } + + //--------------Test file_descriptor_sink---------------------------------// + + { + temp_file temp; + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file, 0); + BOOST_CHECK(out->is_open()); + write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chars with no buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file, 0); + BOOST_CHECK(out->is_open()); + write_data_in_chunks(out); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chunks with no buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file); + BOOST_CHECK(out->is_open()); + write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chars with buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file); + BOOST_CHECK(out->is_open()); + write_data_in_chunks(out); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chunks with buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + // set up the tests + { + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file); + write_data_in_chunks(out); + out.close(); + file.close(); + } + // test std::ios_base::app + { + file_descriptor_sink file(temp.name(), BOOST_IOS::app); + fdostream out(file); + BOOST_CHECK(out->is_open()); + write_data_in_chars(out); + out.close(); + std::string expected(narrow_data()); + expected += narrow_data(); + BOOST_CHECK_MESSAGE( + compare_container_and_file(expected, temp.name()), + "failed writing to file_descriptor_sink in append mode" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + // test std::ios_base::trunc + { + file_descriptor_sink file(temp.name(), BOOST_IOS::trunc); + fdostream out(file); + BOOST_CHECK(out->is_open()); + write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in trunc mode" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + // test illegal flag combinations + { + BOOST_CHECK_THROW( + file_descriptor_sink(temp.name(), + BOOST_IOS::trunc | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_sink(temp.name(), + BOOST_IOS::in), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_sink(temp.name(), + BOOST_IOS::in | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_sink(temp.name(), + BOOST_IOS::in | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor_sink(temp.name(), + BOOST_IOS::in | BOOST_IOS::trunc | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + } + } + + //--Test seeking with file_descriptor_source and file_descriptor_sink-----// + + test_file test3; + { + file_descriptor_sink sink(test3.name()); + fdostream out(sink); + BOOST_CHECK(out->is_open()); + BOOST_CHECK_MESSAGE( + test_output_seekable(out), + "failed seeking within a file_descriptor_sink" + ); + out->close(); + BOOST_CHECK(!out->is_open()); + + file_descriptor_source source(test3.name()); + fdistream in(source); + BOOST_CHECK(in->is_open()); + BOOST_CHECK_MESSAGE( + test_input_seekable(in), + "failed seeking within a file_descriptor_source" + ); + in->close(); + BOOST_CHECK(!in->is_open()); + } + + //--------------Test file_descriptor--------------------------------------// + + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::in | + BOOST_IOS::out | + BOOST_IOS::trunc | + BOOST_IOS::binary ); + fdstream io(file, BUFSIZ); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within a file_descriptor, in chars" + ); + } + + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::in | + BOOST_IOS::out | + BOOST_IOS::trunc | + BOOST_IOS::binary ); + fdstream io(file, BUFSIZ); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within a file_descriptor, in chunks" + ); + } + + //--------------Test read-only file_descriptor----------------------------// + + { + fdstream first(file_descriptor(test1.name(), BOOST_IOS::in), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + write_data_in_chars(first); + BOOST_CHECK(first.fail()); + first.clear(); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from file_descriptor in chars with no buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + fdstream first(file_descriptor(test1.name(), BOOST_IOS::in), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + write_data_in_chunks(first); + BOOST_CHECK(first.fail()); + first.clear(); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from file_descriptor in chunks with no buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + file_descriptor file(test1.name(), BOOST_IOS::in); + fdstream first(file); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + write_data_in_chars(first); + BOOST_CHECK(first.fail()); + first.clear(); + first.seekg(0, BOOST_IOS::beg); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from file_descriptor in chars with buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + { + file_descriptor file(test1.name(), BOOST_IOS::in); + fdstream first(file); + ifstream second(test2.name().c_str()); + BOOST_CHECK(first->is_open()); + write_data_in_chunks(first); + BOOST_CHECK(first.fail()); + first.clear(); + first.seekg(0, BOOST_IOS::beg); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from file_descriptor in chunks with buffer" + ); + first->close(); + BOOST_CHECK(!first->is_open()); + } + + //--------------Test write-only file_descriptor---------------------------// + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::out | + BOOST_IOS::trunc ); + fdstream out(file, 0); + BOOST_CHECK(out->is_open()); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + write_data_in_chars(out); + out.seekg(0, BOOST_IOS::beg); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor in chars with no buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::out | + BOOST_IOS::trunc ); + fdstream out(file, 0); + BOOST_CHECK(out->is_open()); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + write_data_in_chunks(out); + out.seekg(0, BOOST_IOS::beg); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chunks with no buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::out | + BOOST_IOS::trunc ); + fdstream out(file); + BOOST_CHECK(out->is_open()); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + write_data_in_chars(out); + out.seekg(0, BOOST_IOS::beg); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chars with buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + { + temp_file temp; + file_descriptor file( temp.name(), + BOOST_IOS::out | + BOOST_IOS::trunc ); + fdstream out(file); + BOOST_CHECK(out->is_open()); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + write_data_in_chunks(out); + out.seekg(0, BOOST_IOS::beg); + out.get(); + BOOST_CHECK(out.fail()); + out.clear(); + out.close(); + BOOST_CHECK_MESSAGE( + compare_files(test1.name(), temp.name()), + "failed writing to file_descriptor_sink in chunks with buffer" + ); + file.close(); + BOOST_CHECK(!file.is_open()); + } + + // test illegal flag combinations + { + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::openmode(0)), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::app | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::in | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::in | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::in | BOOST_IOS::app | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::out | BOOST_IOS::app | BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::in | BOOST_IOS::out | BOOST_IOS::app), + BOOST_IOSTREAMS_FAILURE); + BOOST_CHECK_THROW( + file_descriptor(test1.name(), + BOOST_IOS::in | + BOOST_IOS::out | + BOOST_IOS::app | + BOOST_IOS::trunc), + BOOST_IOSTREAMS_FAILURE); + } +} + +template +void file_handle_test_impl(FileDescriptor*) +{ + test_file test1; + test_file test2; + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + { + FileDescriptor device1(handle, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + { + FileDescriptor device1(handle, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle); + } + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + FileDescriptor device1(handle, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_OPEN(handle); + close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + FileDescriptor device1(handle, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle); + device1.close(); + BOOST_CHECK(!device1.is_open()); + BOOST_CHECK_HANDLE_CLOSED(handle); + } + + { + boost_ios::detail::file_handle handle1 = open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = open_file_handle(test2.name()); + { + FileDescriptor device1(handle1, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle1); + device1.open(handle2, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle2); + } + BOOST_CHECK_HANDLE_OPEN(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + close_file_handle(handle1); + close_file_handle(handle2); + } + + { + boost_ios::detail::file_handle handle1 = open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = open_file_handle(test2.name()); + { + FileDescriptor device1(handle1, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle1); + device1.open(handle2, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + } + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_CLOSED(handle2); + } + + { + boost_ios::detail::file_handle handle1 = open_file_handle(test1.name()); + boost_ios::detail::file_handle handle2 = open_file_handle(test2.name()); + { + FileDescriptor device1(handle1, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle1); + device1.open(handle2, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle2); + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + } + BOOST_CHECK_HANDLE_CLOSED(handle1); + BOOST_CHECK_HANDLE_OPEN(handle2); + close_file_handle(handle2); + } + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + { + FileDescriptor device1; + BOOST_CHECK(!device1.is_open()); + device1.open(handle, boost_ios::never_close_handle); + BOOST_CHECK(device1.handle() == handle); + BOOST_CHECK_HANDLE_OPEN(handle); + } + BOOST_CHECK_HANDLE_OPEN(handle); + close_file_handle(handle); + } + + { + boost_ios::detail::file_handle handle = open_file_handle(test1.name()); + { + FileDescriptor device1; + BOOST_CHECK(!device1.is_open()); + device1.open(handle, boost_ios::close_handle); + BOOST_CHECK(device1.handle() == handle); + BOOST_CHECK_HANDLE_OPEN(handle); + } + BOOST_CHECK_HANDLE_CLOSED(handle); + } +} + +void file_handle_test() +{ + file_handle_test_impl((boost_ios::file_descriptor*) 0); + file_handle_test_impl((boost_ios::file_descriptor_source*) 0); + file_handle_test_impl((boost_ios::file_descriptor_sink*) 0); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("file_descriptor test"); + test->add(BOOST_TEST_CASE(&file_descriptor_test)); + test->add(BOOST_TEST_CASE(&file_handle_test)); + return test; +} diff --git a/libs/iostreams/test/file_test.cpp b/libs/iostreams/test/file_test.cpp new file mode 100644 index 0000000000..ac5035bfa5 --- /dev/null +++ b/libs/iostreams/test/file_test.cpp @@ -0,0 +1,63 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using std::ifstream; +using boost::unit_test::test_suite; + +void file_test() +{ + test_file test; + + //--------------Test file_source------------------------------------------// + + { + file_source f(test.name()); + BOOST_CHECK(f.is_open()); + f.close(); + BOOST_CHECK(!f.is_open()); + f.open(test.name()); + BOOST_CHECK(f.is_open()); + } + + //--------------Test file_sink--------------------------------------------// + + { + file_sink f(test.name()); + BOOST_CHECK(f.is_open()); + f.close(); + BOOST_CHECK(!f.is_open()); + f.open(test.name()); + BOOST_CHECK(f.is_open()); + } + + //--------------Test file-------------------------------------------------// + + { + file f(test.name()); + BOOST_CHECK(f.is_open()); + f.close(); + BOOST_CHECK(!f.is_open()); + f.open(test.name()); + BOOST_CHECK(f.is_open()); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("file test"); + test->add(BOOST_TEST_CASE(&file_test)); + return test; +} diff --git a/libs/iostreams/test/filter_test.cpp b/libs/iostreams/test/filter_test.cpp new file mode 100644 index 0000000000..0f1b708993 --- /dev/null +++ b/libs/iostreams/test/filter_test.cpp @@ -0,0 +1,98 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include "detail/filters.hpp" + +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +const std::string lower = + "in addition to providing an abstract framework the " + "library provides a number of concrete filters, sources " + "and sinks which serve as example applications of the " + "library but are also useful in their own right. these " + "include components for accessing memory-mapped files, " + "for file access via operating system file descriptors, " + "for code conversion, for text filtering with regular " + "expressions, for line-ending conversion and for " + "compression and decompression in the zlib, gzip and " + "bzip2 formats."; + +const std::string upper = + "IN ADDITION TO PROVIDING AN ABSTRACT FRAMEWORK THE " + "LIBRARY PROVIDES A NUMBER OF CONCRETE FILTERS, SOURCES " + "AND SINKS WHICH SERVE AS EXAMPLE APPLICATIONS OF THE " + "LIBRARY BUT ARE ALSO USEFUL IN THEIR OWN RIGHT. THESE " + "INCLUDE COMPONENTS FOR ACCESSING MEMORY-MAPPED FILES, " + "FOR FILE ACCESS VIA OPERATING SYSTEM FILE DESCRIPTORS, " + "FOR CODE CONVERSION, FOR TEXT FILTERING WITH REGULAR " + "EXPRESSIONS, FOR LINE-ENDING CONVERSION AND FOR " + "COMPRESSION AND DECOMPRESSION IN THE ZLIB, GZIP AND " + "BZIP2 FORMATS."; + +struct toupper_dual_use_filter : public dual_use_filter { + template + int get(Source& s) + { + int c = boost::iostreams::get(s); + return c != EOF && c != WOULD_BLOCK ? + std::toupper((unsigned char) c) : + c; + } + template + bool put(Sink& s, char c) + { + return boost::iostreams::put( + s, (char) std::toupper((unsigned char) c) + ); + } +}; + +struct tolower_dual_use_filter : public dual_use_filter { + template + int get(Source& s) + { + int c = boost::iostreams::get(s); + return c != EOF && c != WOULD_BLOCK ? + std::tolower((unsigned char) c) : + c; + } + template + bool put(Sink& s, char c) + { + return boost::iostreams::put( + s, (char) std::tolower((unsigned char) c) + ); + } +}; + +void filter_test() +{ + BOOST_CHECK(test_input_filter(toupper_filter(), lower, upper)); + BOOST_CHECK(test_input_filter(toupper_multichar_filter(), lower, upper)); + BOOST_CHECK(test_input_filter(toupper_dual_use_filter(), lower, upper)); + BOOST_CHECK(test_output_filter(tolower_filter(), upper, lower)); + BOOST_CHECK(test_output_filter(tolower_multichar_filter(), upper, lower)); + BOOST_CHECK(test_output_filter(tolower_dual_use_filter(), upper, lower)); + BOOST_CHECK(test_filter_pair(tolower_filter(), toupper_filter(), upper)); + BOOST_CHECK( + test_filter_pair( tolower_multichar_filter(), + toupper_multichar_filter(), upper ) + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("filter test"); + test->add(BOOST_TEST_CASE(&filter_test)); + return test; +} diff --git a/libs/iostreams/test/filtering_stream_flush_test.hpp b/libs/iostreams/test/filtering_stream_flush_test.hpp new file mode 100644 index 0000000000..28b29060e1 --- /dev/null +++ b/libs/iostreams/test/filtering_stream_flush_test.hpp @@ -0,0 +1,36 @@ +// (C) Copyright 2011 Steven Watanabe +// 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. + +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void test_filtering_ostream_flush() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + lowercase_file lower; + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_filter()); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chars(out); + out.flush(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chars with an " + "output filter" + ); + } +} diff --git a/libs/iostreams/test/filtering_stream_test.cpp b/libs/iostreams/test/filtering_stream_test.cpp new file mode 100644 index 0000000000..be3e5205d4 --- /dev/null +++ b/libs/iostreams/test/filtering_stream_test.cpp @@ -0,0 +1,52 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include "read_input_test.hpp" +#include "read_bidir_test.hpp" +#include "read_seekable_test.hpp" +#include "read_bidir_streambuf_test.hpp" +#include "read_input_istream_test.hpp" +#include "write_output_test.hpp" +#include "write_bidir_test.hpp" +#include "write_seekable_test.hpp" +#include "write_output_iterator_test.hpp" +#include "write_bidir_streambuf_test.hpp" +#include "write_output_ostream_test.hpp" +#include "read_input_filter_test.hpp" +#include "read_bidir_filter_test.hpp" +#include "write_output_filter_test.hpp" +#include "write_bidir_filter_test.hpp" +#include "seek_test.hpp" +#include "putback_test.hpp" +#include "filtering_stream_flush_test.hpp" + +using boost::unit_test::test_suite; + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("filtering_stream test"); + test->add(BOOST_TEST_CASE(&read_input_test)); + test->add(BOOST_TEST_CASE(&read_bidirectional_test)); + test->add(BOOST_TEST_CASE(&read_seekable_test)); + test->add(BOOST_TEST_CASE(&read_bidirectional_streambuf_test)); + test->add(BOOST_TEST_CASE(&read_input_istream_test)); + test->add(BOOST_TEST_CASE(&write_output_test)); + test->add(BOOST_TEST_CASE(&write_bidirectional_test)); + test->add(BOOST_TEST_CASE(&write_seekable_test)); + test->add(BOOST_TEST_CASE(&write_output_iterator_test)); + test->add(BOOST_TEST_CASE(&write_bidirectional_streambuf_test)); + test->add(BOOST_TEST_CASE(&write_output_ostream_test)); + test->add(BOOST_TEST_CASE(&read_input_filter_test)); + test->add(BOOST_TEST_CASE(&read_bidirectional_filter_test)); + test->add(BOOST_TEST_CASE(&write_output_filter_test)); + test->add(BOOST_TEST_CASE(&write_bidirectional_filter_test)); + test->add(BOOST_TEST_CASE(&seek_test)); + test->add(BOOST_TEST_CASE(&putback_test)); + test->add(BOOST_TEST_CASE(&test_filtering_ostream_flush)); + return test; +} diff --git a/libs/iostreams/test/finite_state_filter_test.cpp b/libs/iostreams/test/finite_state_filter_test.cpp new file mode 100644 index 0000000000..698fc8b792 --- /dev/null +++ b/libs/iostreams/test/finite_state_filter_test.cpp @@ -0,0 +1,182 @@ +// (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. + +#include +#ifdef BOOST_NO_STD_LOCALE +# error std::locale not supported on this platform +#else + +# include +# include // failure. +# include +# include +# include +# include +# include "../example/finite_state_filter.hpp" + +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +const std::string posix = // 'unix' is sometimes a macro. + "When I was one-and-twenty\n" + "I heard a wise man say,\n" + "'Give crowns and pounds and guineas\n" + "But not your heart away;\n" + "\n" + "Give pearls away and rubies\n" + "But keep your fancy free.'\n" + "But I was one-and-twenty,\n" + "No use to talk to me.\n" + "\n" + "When I was one-and-twenty\n" + "I heard him say again,\n" + "'The heart out of the bosom\n" + "Was never given in vain;\n" + "'Tis paid with sighs a plenty\n" + "And sold for endless rue.'\n" + "And I am two-and-twenty,\n" + "And oh, 'tis true, 'tis true."; + +const std::string dos = + "When I was one-and-twenty\r\n" + "I heard a wise man say,\r\n" + "'Give crowns and pounds and guineas\r\n" + "But not your heart away;\r\n" + "\r\n" + "Give pearls away and rubies\r\n" + "But keep your fancy free.'\r\n" + "But I was one-and-twenty,\r\n" + "No use to talk to me.\r\n" + "\r\n" + "When I was one-and-twenty\r\n" + "I heard him say again,\r\n" + "'The heart out of the bosom\r\n" + "Was never given in vain;\r\n" + "'Tis paid with sighs a plenty\r\n" + "And sold for endless rue.'\r\n" + "And I am two-and-twenty,\r\n" + "And oh, 'tis true, 'tis true."; + +const std::string comments = + "When I was /*one-and-twenty\n" + "I he*/ard a wise/ man say,\n" + "'Give cr//*owns *and po**/unds and guineas\n" + "But n*/ot yo*/ur he/*a*/rt /**/away;\n"; + +const std::string no_comments = + "When I was " + "ard a wise/ man say,\n" + "'Give cr/unds and guineas\n" + "But n*/ot yo*/ur hert away;\n"; + +struct identity_fsm + : io::finite_state_machine +{ + void on_any(char c) { push(c); } + typedef boost::mpl::vector0<> transition_table; +}; + +struct dos2unix_fsm : io::finite_state_machine { + BOOST_IOSTREAMS_FSM(dos2unix_fsm) // Define skip and push. + typedef dos2unix_fsm self; + typedef boost::mpl::vector< + row, initial_state, &self::skip>, + row + > transition_table; +}; + +struct unix2dos_fsm : io::finite_state_machine { + BOOST_IOSTREAMS_FSM(unix2dos_fsm) // Define skip and push. + typedef unix2dos_fsm self; + + void on_lf(char) { push('\r'); push('\n'); } + + typedef boost::mpl::vector< + row, initial_state, &self::on_lf>, + row + > transition_table; +}; + +struct uncommenting_fsm : io::finite_state_machine { + BOOST_IOSTREAMS_FSM(uncommenting_fsm) // Define skip and push. + typedef uncommenting_fsm self; + + static const int no_comment = initial_state; + static const int pre_comment = no_comment + 1; + static const int comment = pre_comment + 1; + static const int post_comment = comment + 1; + + void push_slash(char c) { push('/'); push(c); } + + typedef boost::mpl::vector< + row, pre_comment, &self::skip>, + row, + row, comment, &self::skip>, + row, pre_comment, &self::push>, + row, + row, post_comment, &self::skip>, + row, + row, no_comment, &self::skip>, + row, post_comment, &self::skip>, + row + > transition_table; +}; + +void finite_state_filter_test() +{ + using namespace std; + + typedef io::finite_state_filter identity_filter; + typedef io::finite_state_filter dos2unix_filter; + typedef io::finite_state_filter unix2dos_filter; + typedef io::finite_state_filter uncommenting_filter; + + // Test identity_filter. + + BOOST_CHECK( + io::test_input_filter(identity_filter(), dos, dos) + ); + BOOST_CHECK( + io::test_output_filter(identity_filter(), dos, dos) + ); + + // Test dos2unix_filter. + + BOOST_CHECK( + io::test_input_filter(dos2unix_filter(), dos, posix) + ); + BOOST_CHECK( + io::test_output_filter(dos2unix_filter(), dos, posix) + ); + + // Test unix2dos_filter. + + BOOST_CHECK( + io::test_input_filter(unix2dos_filter(), posix, dos) + ); + BOOST_CHECK( + io::test_output_filter(unix2dos_filter(), posix, dos) + ); + + // Test uncommenting_filter. + + BOOST_CHECK( + io::test_input_filter(uncommenting_filter(), comments, no_comments) + ); + BOOST_CHECK( + io::test_output_filter(uncommenting_filter(), comments, no_comments) + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("example test"); + test->add(BOOST_TEST_CASE(&finite_state_filter_test)); + return test; +} + +#endif // #ifdef BOOST_NO_STD_LOCALE //---------------------------------------// diff --git a/libs/iostreams/test/flush_test.cpp b/libs/iostreams/test/flush_test.cpp new file mode 100644 index 0000000000..edb72ca3d9 --- /dev/null +++ b/libs/iostreams/test/flush_test.cpp @@ -0,0 +1,145 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include // equal. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +void flush_test() +{ + { + stream_buffer null; + null.open(null_sink()); + BOOST_CHECK_MESSAGE( + iostreams::flush(null), + "failed flushing stream_buffer" + ); + BOOST_CHECK_MESSAGE( + null.strict_sync(), + "failed strict-syncing stream_buffer with " + "non-flushable resource" + ); + } + + { + stream null; + null.open(null_sink()); + BOOST_CHECK_MESSAGE( + iostreams::flush(null), + "failed flushing stream" + ); + BOOST_CHECK_MESSAGE( + null.strict_sync(), + "failed strict-syncing stream with " + "non-flushable resource" + ); + } + + { + filtering_ostream null; + null.push(null_sink()); + BOOST_CHECK_MESSAGE( + iostreams::flush(null), + "failed flushing filtering_ostream" + ); + BOOST_CHECK_MESSAGE( + null.strict_sync(), + "failed strict-syncing filtering_ostream with " + "non-flushable resource" + ); + } + + { + filtering_ostream null; + null.push(tolower_filter()); + null.push(null_sink()); + BOOST_CHECK_MESSAGE( + iostreams::flush(null), + "failed flushing filtering_ostream with non-flushable filter" + ); + BOOST_CHECK_MESSAGE( + !null.strict_sync(), + "strict-syncing filtering_ostream with " + "non-flushable filter succeeded" + ); + } + + { + vector dest1; + vector dest2; + filtering_ostream out; + out.set_auto_close(false); + out.push(flushable_output_filter()); + + // Write to dest1. + out.push(iostreams::back_inserter(dest1)); + write_data_in_chunks(out); + out.flush(); + + // Write to dest2. + out.pop(); + out.push(iostreams::back_inserter(dest2)); + write_data_in_chunks(out); + out.flush(); + + BOOST_CHECK_MESSAGE( + dest1.size() == dest2.size() && + std::equal(dest1.begin(), dest1.end(), dest2.begin()), + "failed flush filtering_ostream with auto_close disabled" + ); + } + + { + vector dest1; + vector dest2; + filtering_ostream out; + out.set_auto_close(false); + out.push(flushable_output_filter()); + out.push(flushable_output_filter()); + + // Write to dest1. + out.push(iostreams::back_inserter(dest1)); + write_data_in_chunks(out); + out.flush(); + + // Write to dest2. + out.pop(); + out.push(iostreams::back_inserter(dest2)); + write_data_in_chunks(out); + out.flush(); + + BOOST_CHECK_MESSAGE( + dest1.size() == dest2.size() && + std::equal(dest1.begin(), dest1.end(), dest2.begin()), + "failed flush filtering_ostream with two flushable filters " + "with auto_close disabled" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("flush test"); + test->add(BOOST_TEST_CASE(&flush_test)); + return test; +} diff --git a/libs/iostreams/test/grep_test.cpp b/libs/iostreams/test/grep_test.cpp new file mode 100644 index 0000000000..f9af490dd0 --- /dev/null +++ b/libs/iostreams/test/grep_test.cpp @@ -0,0 +1,282 @@ +/* + * 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. + + * File: libs/iostreams/test/grep_test.cpp + * Date: Mon May 26 17:48:45 MDT 2008 + * Copyright: 2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + * + * Tests the class template basic_grep_filter. + */ + +#include + +#include // Make sure ptrdiff_t is in std. +#include +#include // std::ptrdiff_t +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost; +using namespace boost::iostreams; +namespace io = boost::iostreams; +using boost::unit_test::test_suite; + +// List of addresses of US Appeals Courts, from uscourts.gov +std::string addresses = + "John Joseph Moakley United States Courthouse, Suite 2500\n" + "One Courthouse Way\n" + "Boston, MA 02210-3002\n" + "\n" + "Thurgood Marshall United States Courthouse, 18th Floor\n" + "40 Centre Street\n" + "New York, NY 10007-1501\n" + "\n" + "21400 James A. Byrne United States Courthouse\n" + "601 Market Street\n" + "Philadelphia, PA 19106-1729\n" + "\n" + "Lewis F. Powell, Jr. United States Courthouse Annex, Suite 501\n" + "1100 East Main Street\n" + "Richmond, VA 23219-3525\n" + "\n" + "F. Edward Hebert Federal Bldg\n" + "600 South Maestri Place\n" + "New Orleans, LA 70130\n" + "\n" + "Bob Casey United States Courthouse, 1st Floor\n" + "515 Rusk Street\n" + "Houston, TX 77002-2600\n" + "\n" + "Potter Stewart United States Courthouse, Suite 540\n" + "100 East Fifth Street\n" + "Cincinnati, OH 45202\n" + "\n" + "2722 Everett McKinley Dirksen United States Courthouse\n" + "219 South Dearborn Street\n" + "Chicago, IL 60604\n"; + +// Lines containing "United States Courthouse" +std::string us_courthouse = + "John Joseph Moakley United States Courthouse, Suite 2500\n" + "Thurgood Marshall United States Courthouse, 18th Floor\n" + "21400 James A. Byrne United States Courthouse\n" + "Lewis F. Powell, Jr. United States Courthouse Annex, Suite 501\n" + "Bob Casey United States Courthouse, 1st Floor\n" + "Potter Stewart United States Courthouse, Suite 540\n" + "2722 Everett McKinley Dirksen United States Courthouse\n"; + +// Lines not containing "United States Courthouse" +std::string us_courthouse_inv = + "One Courthouse Way\n" + "Boston, MA 02210-3002\n" + "\n" + "40 Centre Street\n" + "New York, NY 10007-1501\n" + "\n" + "601 Market Street\n" + "Philadelphia, PA 19106-1729\n" + "\n" + "1100 East Main Street\n" + "Richmond, VA 23219-3525\n" + "\n" + "F. Edward Hebert Federal Bldg\n" + "600 South Maestri Place\n" + "New Orleans, LA 70130\n" + "\n" + "515 Rusk Street\n" + "Houston, TX 77002-2600\n" + "\n" + "100 East Fifth Street\n" + "Cincinnati, OH 45202\n" + "\n" + "219 South Dearborn Street\n" + "Chicago, IL 60604\n"; + +// Lines containing a state and zip +std::string state_and_zip = + "Boston, MA 02210-3002\n" + "New York, NY 10007-1501\n" + "Philadelphia, PA 19106-1729\n" + "Richmond, VA 23219-3525\n" + "New Orleans, LA 70130\n" + "Houston, TX 77002-2600\n" + "Cincinnati, OH 45202\n" + "Chicago, IL 60604\n"; + +// Lines not containing a state and zip +std::string state_and_zip_inv = + "John Joseph Moakley United States Courthouse, Suite 2500\n" + "One Courthouse Way\n" + "\n" + "Thurgood Marshall United States Courthouse, 18th Floor\n" + "40 Centre Street\n" + "\n" + "21400 James A. Byrne United States Courthouse\n" + "601 Market Street\n" + "\n" + "Lewis F. Powell, Jr. United States Courthouse Annex, Suite 501\n" + "1100 East Main Street\n" + "\n" + "F. Edward Hebert Federal Bldg\n" + "600 South Maestri Place\n" + "\n" + "Bob Casey United States Courthouse, 1st Floor\n" + "515 Rusk Street\n" + "\n" + "Potter Stewart United States Courthouse, Suite 540\n" + "100 East Fifth Street\n" + "\n" + "2722 Everett McKinley Dirksen United States Courthouse\n" + "219 South Dearborn Street\n"; + +// Lines containing at least three words +std::string three_words = + "John Joseph Moakley United States Courthouse, Suite 2500\n" + "One Courthouse Way\n" + "Thurgood Marshall United States Courthouse, 18th Floor\n" + "40 Centre Street\n" + "21400 James A. Byrne United States Courthouse\n" + "601 Market Street\n" + "Lewis F. Powell, Jr. United States Courthouse Annex, Suite 501\n" + "1100 East Main Street\n" + "F. Edward Hebert Federal Bldg\n" + "600 South Maestri Place\n" + "Bob Casey United States Courthouse, 1st Floor\n" + "515 Rusk Street\n" + "Potter Stewart United States Courthouse, Suite 540\n" + "100 East Fifth Street\n" + "2722 Everett McKinley Dirksen United States Courthouse\n" + "219 South Dearborn Street\n"; + +// Lines containing exactly three words +std::string exactly_three_words = + "One Courthouse Way\n" + "40 Centre Street\n" + "601 Market Street\n" + "515 Rusk Street\n"; + +// Lines that don't contain exactly three words +std::string exactly_three_words_inv = + "John Joseph Moakley United States Courthouse, Suite 2500\n" + "Boston, MA 02210-3002\n" + "\n" + "Thurgood Marshall United States Courthouse, 18th Floor\n" + "New York, NY 10007-1501\n" + "\n" + "21400 James A. Byrne United States Courthouse\n" + "Philadelphia, PA 19106-1729\n" + "\n" + "Lewis F. Powell, Jr. United States Courthouse Annex, Suite 501\n" + "1100 East Main Street\n" + "Richmond, VA 23219-3525\n" + "\n" + "F. Edward Hebert Federal Bldg\n" + "600 South Maestri Place\n" + "New Orleans, LA 70130\n" + "\n" + "Bob Casey United States Courthouse, 1st Floor\n" + "Houston, TX 77002-2600\n" + "\n" + "Potter Stewart United States Courthouse, Suite 540\n" + "100 East Fifth Street\n" + "Cincinnati, OH 45202\n" + "\n" + "2722 Everett McKinley Dirksen United States Courthouse\n" + "219 South Dearborn Street\n" + "Chicago, IL 60604\n"; + +void test_filter( grep_filter grep, + const std::string& input, + const std::string& output ); + +void grep_filter_test() +{ + regex match_us_courthouse("\\bUnited States Courthouse\\b"); + regex match_state_and_zip("\\b[A-Z]{2}\\s+[0-9]{5}(-[0-9]{4})?\\b"); + regex match_three_words("\\b\\w+\\s+\\w+\\s+\\w+\\b"); + regex_constants::match_flag_type match_default = + regex_constants::match_default; + + { + grep_filter grep(match_us_courthouse); + test_filter(grep, addresses, us_courthouse); + } + + { + grep_filter grep(match_us_courthouse, match_default, grep::invert); + test_filter(grep, addresses, us_courthouse_inv); + } + + { + grep_filter grep(match_state_and_zip); + test_filter(grep, addresses, state_and_zip); + } + + { + grep_filter grep(match_state_and_zip, match_default, grep::invert); + test_filter(grep, addresses, state_and_zip_inv); + } + + { + grep_filter grep(match_three_words); + test_filter(grep, addresses, three_words); + } + + { + grep_filter grep(match_three_words, match_default, grep::whole_line); + test_filter(grep, addresses, exactly_three_words); + } + + { + int options = grep::whole_line | grep::invert; + grep_filter grep(match_three_words, match_default, options); + test_filter(grep, addresses, exactly_three_words_inv); + } +} + +void test_filter( grep_filter grep, + const std::string& input, + const std::string& output ) +{ + // Count lines in output + std::ptrdiff_t count = std::count(output.begin(), output.end(), '\n'); + + // Test as input filter + { + array_source src(input.data(), input.data() + input.size()); + std::string dest; + io::copy(compose(boost::ref(grep), src), io::back_inserter(dest)); + BOOST_CHECK(dest == output); + BOOST_CHECK(grep.count() == count); + } + + // Test as output filter + { + array_source src(input.data(), input.data() + input.size()); + std::string dest; + io::copy(src, compose(boost::ref(grep), io::back_inserter(dest))); + BOOST_CHECK(dest == output); + BOOST_CHECK(grep.count() == count); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("grep_filter test"); + test->add(BOOST_TEST_CASE(&grep_filter_test)); + return test; +} diff --git a/libs/iostreams/test/gzip_test.cpp b/libs/iostreams/test/gzip_test.cpp new file mode 100644 index 0000000000..fc0eba790e --- /dev/null +++ b/libs/iostreams/test/gzip_test.cpp @@ -0,0 +1,121 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/verification.hpp" + +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +namespace io = boost::iostreams; +using boost::unit_test::test_suite; + +struct gzip_alloc : std::allocator { }; + +void compression_test() +{ + text_sequence data; + + // Test compression and decompression with metadata + for (int i = 0; i < 4; ++i) { + gzip_params params; + if (i & 1) { + params.file_name = "original file name"; + } + if (i & 2) { + params.comment = "detailed file description"; + } + gzip_compressor out(params); + gzip_decompressor in; + BOOST_CHECK( + test_filter_pair( boost::ref(out), + boost::ref(in), + std::string(data.begin(), data.end()) ) + ); + BOOST_CHECK(in.file_name() == params.file_name); + BOOST_CHECK(in.comment() == params.comment); + } + + // Test compression and decompression with custom allocator + BOOST_CHECK( + test_filter_pair( basic_gzip_compressor(), + basic_gzip_decompressor(), + std::string(data.begin(), data.end()) ) + ); +} + +void multiple_member_test() +{ + text_sequence data; + std::vector temp, dest; + + // Write compressed data to temp, twice in succession + filtering_ostream out; + out.push(gzip_compressor()); + out.push(io::back_inserter(temp)); + io::copy(make_iterator_range(data), out); + out.push(io::back_inserter(temp)); + io::copy(make_iterator_range(data), out); + + // Read compressed data from temp into dest + filtering_istream in; + in.push(gzip_decompressor()); + in.push(array_source(&temp[0], temp.size())); + io::copy(in, io::back_inserter(dest)); + + // Check that dest consists of two copies of data + BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size()); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin())); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2)); + + dest.clear(); + io::copy( + array_source(&temp[0], temp.size()), + io::compose(gzip_decompressor(), io::back_inserter(dest))); + + // Check that dest consists of two copies of data + BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size()); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin())); + BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2)); +} + +void array_source_test() +{ + std::string data = "simple test string."; + std::string encoded; + + filtering_ostream out; + out.push(gzip_compressor()); + out.push(io::back_inserter(encoded)); + io::copy(make_iterator_range(data), out); + + std::string res; + io::array_source src(encoded.data(),encoded.length()); + io::copy(io::compose(io::gzip_decompressor(), src), io::back_inserter(res)); + + BOOST_CHECK_EQUAL(data, res); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("gzip test"); + test->add(BOOST_TEST_CASE(&compression_test)); + test->add(BOOST_TEST_CASE(&multiple_member_test)); + test->add(BOOST_TEST_CASE(&array_source_test)); + return test; +} diff --git a/libs/iostreams/test/invert_test.cpp b/libs/iostreams/test/invert_test.cpp new file mode 100644 index 0000000000..0621653f47 --- /dev/null +++ b/libs/iostreams/test/invert_test.cpp @@ -0,0 +1,70 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/filters.hpp" +#include "detail/operation_sequence.hpp" +#include "detail/temp_file.hpp" + +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +void read_write_test() +{ + + test_file test; + lowercase_file lower; + uppercase_file upper; + + BOOST_CHECK( test_input_filter( + invert(tolower_filter()), + file_source(test.name(), in_mode), + file_source(lower.name(), in_mode) ) ); + + BOOST_CHECK( test_output_filter( + invert(toupper_filter()), + file_source(test.name(), in_mode), + file_source(upper.name(), in_mode) ) ); +} + +void close_test() +{ + // Invert an output filter + { + operation_sequence seq; + chain ch; + ch.push(io::invert(closable_filter(seq.new_operation(2)))); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Invert an input filter + { + operation_sequence seq; + chain ch; + ch.push(io::invert(closable_filter(seq.new_operation(1)))); + 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("reverse test"); + test->add(BOOST_TEST_CASE(&read_write_test)); + test->add(BOOST_TEST_CASE(&close_test)); + return test; +} diff --git a/libs/iostreams/test/large_file_test.cpp b/libs/iostreams/test/large_file_test.cpp new file mode 100644 index 0000000000..c6cc8d8526 --- /dev/null +++ b/libs/iostreams/test/large_file_test.cpp @@ -0,0 +1,446 @@ +/* + * 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. + * + * Tests seeking with a file_descriptor using large file offsets. + * + * File: libs/iostreams/test/large_file_test.cpp + * Date: Tue Dec 25 21:34:47 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#include // SEEK_SET, etc. +#include +#include +#include // BOOST_STRINGIZE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + // OS-specific headers for low-level i/o. + +#include // file opening flags. +#include // file access permissions. +#ifdef BOOST_IOSTREAMS_WINDOWS +# include // low-level file i/o. +# define WINDOWS_LEAN_AND_MEAN +# include +# ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +# endif +#else +# include // mode_t. +# include // low-level file i/o. +#endif + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using boost::unit_test::test_suite; + +//------------------Definition of constants-----------------------------------// + +const stream_offset gigabyte = 1073741824; +const stream_offset file_size = // Some compilers complain about "8589934593" + gigabyte * static_cast(8) + static_cast(1); +const int offset_list[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, // Seek by 1GB + 0, 2, 1, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, // Seek by 2GB + 6, 7, 5, 6, 4, 5, 3, 4, 2, 3, 1, 2, + 0, 3, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, // Seek by 3GB + 5, 7, 4, 6, 3, 5, 2, 4, 1, + 0, 4, 1, 5, 2, 6, 3, 7, 4, 8, // Seek by 4GB + 4, 7, 3, 6, 2, 5, 1, 4, + 0, 5, 1, 6, 2, 7, 3, 8, 3, 7, 2, 6, 1, 5, // Seek by 5GB + 0, 6, 1, 7, 2, 8, 2, 7, 1, 6, // Seek by 6GB + 0, 7, 1, 8, 1, 7, // Seek by 7GB + 0, 8, 0 }; // Seek by 8GB +const int offset_list_length = sizeof(offset_list) / sizeof(int); +#ifdef LARGE_FILE_TEMP +# define BOOST_FILE_NAME BOOST_STRINGIZE(LARGE_FILE_TEMP) +# define BOOST_KEEP_FILE false +#else +# define BOOST_FILE_NAME BOOST_STRINGIZE(LARGE_FILE_KEEP) +# define BOOST_KEEP_FILE true +#endif + +//------------------Definition of remove_large_file---------------------------// + +// Removes the large file +void remove_large_file() +{ +#ifdef BOOST_IOSTREAMS_WINDOWS + DeleteFile(TEXT(BOOST_FILE_NAME)); +#else + unlink(BOOST_FILE_NAME); +#endif +} + +//------------------Definition of large_file_exists---------------------------// + +// Returns true if the large file exists, has the correct size, and has been +// modified since the last commit affecting this source file; if the file exists +// but is invalid, deletes the file. +bool large_file_exists() +{ + // Last mod date + time_t last_mod; + +#ifdef BOOST_IOSTREAMS_WINDOWS + + // Check existence + WIN32_FIND_DATA info; + HANDLE hnd = FindFirstFile(TEXT(BOOST_FILE_NAME), &info); + if (hnd == INVALID_HANDLE_VALUE) + return false; + + // Check size + FindClose(hnd); + stream_offset size = + (static_cast(info.nFileSizeHigh) << 32) + + static_cast(info.nFileSizeLow); + if (size != file_size) { + remove_large_file(); + return false; + } + + // Fetch last mod date + SYSTEMTIME stime; + if (!FileTimeToSystemTime(&info.ftLastWriteTime, &stime)) { + remove_large_file(); + return false; + } + tm ctime; + ctime.tm_year = stime.wYear - 1900; + ctime.tm_mon = stime.wMonth - 1; + ctime.tm_mday = stime.wDay; + ctime.tm_hour = stime.wHour; + ctime.tm_min = stime.wMinute; + ctime.tm_sec = stime.wSecond; + ctime.tm_isdst = 0; + last_mod = mktime(&ctime); + +#else + + // Check existence + struct BOOST_IOSTREAMS_FD_STAT info; + if (BOOST_IOSTREAMS_FD_STAT(BOOST_FILE_NAME, &info)) + return false; + + // Check size + if (info.st_size != file_size) { + remove_large_file(); + return false; + } + + // Fetch last mod date + last_mod = info.st_mtime; + +#endif + + // Fetch last mod date of this file ("large_file_test.cpp") + string timestamp = + "$Date: 2009-05-20 15:41:20 -0400 (Wed, 20 May 2009) $"; + if (timestamp.size() != 53) { // Length of auto-generated SVN timestamp + remove_large_file(); + return false; + } + tm commit; + try { + commit.tm_year = lexical_cast(timestamp.substr(7, 4)) - 1900; + commit.tm_mon = lexical_cast(timestamp.substr(12, 2)) - 1; + commit.tm_mday = lexical_cast(timestamp.substr(15, 2)); + commit.tm_hour = lexical_cast(timestamp.substr(18, 2)); + commit.tm_min = lexical_cast(timestamp.substr(21, 2)); + commit.tm_sec = lexical_cast(timestamp.substr(24, 2)); + } catch (const bad_lexical_cast&) { + remove_large_file(); + return false; + } + + // If last commit was two days or more before file timestamp, existing + // file is okay; otherwise, it must be regenerated (the two-day window + // compensates for time zone differences) + return difftime(last_mod, mktime(&commit)) >= 60 * 60 * 48; +} + +//------------------Definition of map_large_file------------------------------// + +// Initializes the large file by mapping it in small segments. This is an +// optimization for Win32; the straightforward implementation using WriteFile +// and SetFilePointer (see the Borland workaropund below) is painfully slow. +bool map_large_file() +{ + for (stream_offset z = 0; z <= 8; ++z) { + try { + mapped_file_params params; + params.path = BOOST_FILE_NAME; + params.offset = z * gigabyte; + params.length = 1; + params.mode = BOOST_IOS::out; + mapped_file file(params); + file.begin()[0] = z + 1; + } catch (const std::exception&) { + remove_large_file(); + return false; + } + } + return true; +} + +//------------------Definition of create_large_file---------------------------// + +// Creates and initializes the large file if it does not already exist. The file +// looks like this: +// +// 0 1GB 2GB 3GB 4GB 5GB 6GB 7GB 8GB +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 1.....2.....3.....4.....5.....6.....7.....8.....9 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// where the characters 1-9 appear at offsets that are multiples of 1GB and the +// dots represent uninitialized data. +bool create_large_file() +{ + // If file exists, has correct size, and is recent, we're done + if (BOOST_KEEP_FILE && large_file_exists()) + return true; + +#ifdef BOOST_IOSTREAMS_WINDOWS + + // Create file + HANDLE hnd = + CreateFile( + TEXT(BOOST_FILE_NAME), + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (!hnd) + return false; + + // Set file pointer + LONG off_low = static_cast(file_size & 0xffffffff); + LONG off_high = static_cast(file_size >> 32); + if ( SetFilePointer(hnd, off_low, &off_high, FILE_BEGIN) == + INVALID_SET_FILE_POINTER && + GetLastError() != NO_ERROR ) + { + CloseHandle(hnd); + remove_large_file(); + return false; + } + + // Set file size + if (!SetEndOfFile(hnd)) { + CloseHandle(hnd); + remove_large_file(); + return false; + } + +# if !defined(__BORLANDC__) || __BORLANDC__ < 0x582 || __BORLANDC__ >= 0x592 + + // Close handle; all further access is via mapped_file + CloseHandle(hnd); + + // Initialize file data + return map_large_file(); + +# else // Borland >= 5.8.2 and Borland < 5.9.2 + + // Initialize file data (very slow, even though only 9 writes are required) + for (stream_offset z = 0; z <= 8; ++z) { + + // Seek + LONG off_low = static_cast((z * gigabyte) & 0xffffffff); // == 0 + LONG off_high = static_cast((z * gigabyte) >> 32); + if ( SetFilePointer(hnd, off_low, &off_high, FILE_BEGIN) == + INVALID_SET_FILE_POINTER && + GetLastError() != NO_ERROR ) + { + CloseHandle(hnd); + remove_large_file(); + return false; + } + + // Write a character + char buf[1] = { z + 1 }; + DWORD result; + BOOL success = WriteFile(hnd, buf, 1, &result, NULL); + if (!success || result != 1) { + CloseHandle(hnd); + remove_large_file(); + return false; + } + } + + // Close file + CloseHandle(hnd); + return true; + +# endif // Borland workaround +#else // #ifdef BOOST_IOSTREAMS_WINDOWS + + // Create file + int oflag = O_WRONLY | O_CREAT; + #ifdef _LARGEFILE64_SOURCE + oflag |= O_LARGEFILE; + #endif + mode_t pmode = + S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH; + int fd = BOOST_IOSTREAMS_FD_OPEN(BOOST_FILE_NAME, oflag, pmode); + if (fd == -1) + return false; + + // Set file size + if (BOOST_IOSTREAMS_FD_TRUNCATE(fd, file_size)) { + BOOST_IOSTREAMS_FD_CLOSE(fd); + return false; + } + +# ifndef __CYGWIN__ + + // Initialize file data + for (int z = 0; z <= 8; ++z) { + + // Seek + BOOST_IOSTREAMS_FD_OFFSET off = + BOOST_IOSTREAMS_FD_SEEK( + fd, + static_cast(z * gigabyte), + SEEK_SET + ); + if (off == -1) { + BOOST_IOSTREAMS_FD_CLOSE(fd); + return false; + } + + // Write a character + char buf[1] = { z + 1 }; + if (BOOST_IOSTREAMS_FD_WRITE(fd, buf, 1) == -1) { + BOOST_IOSTREAMS_FD_CLOSE(fd); + return false; + } + } + + // Close file + BOOST_IOSTREAMS_FD_CLOSE(fd); + return true; + +# else // Cygwin + + // Close descriptor; all further access is via mapped_file + BOOST_IOSTREAMS_FD_CLOSE(fd); + + // Initialize file data + return map_large_file(); + +# endif +#endif // #ifdef BOOST_IOSTREAMS_WINDOWS +} + +//------------------Definition of large_file----------------------------------// + +// RAII utility +class large_file { +public: + large_file() { exists_ = create_large_file(); } + ~large_file() { if (!BOOST_KEEP_FILE) remove_large_file(); } + bool exists() const { return exists_; } + const char* path() const { return BOOST_FILE_NAME; } +private: + bool exists_; +}; + +//------------------Definition of check_character-----------------------------// + +// Verify that the given file contains the given character at the current +// position +bool check_character(file_descriptor_source& file, char value) +{ + char buf[1]; + int amt; + BOOST_CHECK_NO_THROW(amt = file.read(buf, 1)); + BOOST_CHECK_MESSAGE(amt == 1, "failed reading character"); + BOOST_CHECK_NO_THROW(file.seek(-1, BOOST_IOS::cur)); + return buf[0] == value; +} + +//------------------Definition of large_file_test-----------------------------// + +void large_file_test() +{ + BOOST_REQUIRE_MESSAGE( + sizeof(stream_offset) >= 8, + "large offsets not supported" + ); + + // Prepare file and file descriptor + large_file large; + file_descriptor_source file; + BOOST_REQUIRE_MESSAGE( + large.exists(), "failed creating file \"" << BOOST_FILE_NAME << '"' + ); + BOOST_CHECK_NO_THROW(file.open(large.path(), BOOST_IOS::binary)); + + // Test seeking using ios_base::beg + for (int z = 0; z < offset_list_length; ++z) { + char value = offset_list[z] + 1; + stream_offset off = + static_cast(offset_list[z]) * gigabyte; + BOOST_CHECK_NO_THROW(file.seek(off, BOOST_IOS::beg)); + BOOST_CHECK_MESSAGE( + check_character(file, value), + "failed validating seek" + ); + } + + // Test seeking using ios_base::end + for (int z = 0; z < offset_list_length; ++z) { + char value = offset_list[z] + 1; + stream_offset off = + -static_cast(8 - offset_list[z]) * gigabyte - 1; + BOOST_CHECK_NO_THROW(file.seek(off, BOOST_IOS::end)); + BOOST_CHECK_MESSAGE( + check_character(file, value), + "failed validating seek" + ); + } + + // Test seeking using ios_base::cur + for (int next, cur = 0, z = 0; z < offset_list_length; ++z, cur = next) { + next = offset_list[z]; + char value = offset_list[z] + 1; + stream_offset off = static_cast(next - cur) * gigabyte; + BOOST_CHECK_NO_THROW(file.seek(off, BOOST_IOS::cur)); + BOOST_CHECK_MESSAGE( + check_character(file, value), + "failed validating seek" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("execute test"); + test->add(BOOST_TEST_CASE(&large_file_test)); + return test; +} diff --git a/libs/iostreams/test/line_filter_test.cpp b/libs/iostreams/test/line_filter_test.cpp new file mode 100644 index 0000000000..2629daa15e --- /dev/null +++ b/libs/iostreams/test/line_filter_test.cpp @@ -0,0 +1,99 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include "detail/constants.hpp" +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +// Must come last. +#include // BCC 5.x. + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +struct toupper_line_filter : line_filter { + std::string do_filter(const std::string& line) + { + std::string result(line); + for ( std::string::size_type z = 0, len = line.size(); + z < len; + ++z ) + { + result[z] = std::toupper((unsigned char) result[z]); + } + return result; + } +}; + +bool compare_streams_in_lines(std::istream& first, std::istream& second) +{ + do { + std::string line_one; + std::string line_two; + std::getline(first, line_one); + std::getline(second, line_two); + if (line_one != line_two || first.eof() != second.eof()) + return false; + } while (!first.eof()); + return true; +} + +void read_line_filter() +{ + test_file src; + uppercase_file upper; + filtering_istream first; + first.push(toupper_line_filter()); + first.push(file_source(src.name(), in_mode)); + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_lines(first, second), + "failed reading from a line_filter" + ); +} + +void write_line_filter() +{ + test_file data; + temp_file dest; + uppercase_file upper; + + filtering_ostream out; + out.push(toupper_line_filter()); + out.push(file_sink(dest.name(), out_mode)); + copy(file_source(data.name(), in_mode), out); + out.reset(); + + ifstream first(dest.name().c_str()); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_lines(first, second), + "failed writing to a line_filter" + ); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("line_filter test"); + test->add(BOOST_TEST_CASE(&read_line_filter)); + test->add(BOOST_TEST_CASE(&write_line_filter)); + return test; +} + +#include // BCC 5.x. + diff --git a/libs/iostreams/test/mapped_file_test.cpp b/libs/iostreams/test/mapped_file_test.cpp new file mode 100644 index 0000000000..b7dd0c8154 --- /dev/null +++ b/libs/iostreams/test/mapped_file_test.cpp @@ -0,0 +1,329 @@ +// (C) Copyright Jorge Lodos 2008 +// (C) Copyright Jonathan Turkanis 2004 +// 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. + +// This is the original (boost 1.34) boost::iostream test for the mapped files with the +// following modifications: +// 1. The namespace for the mapped file was changed to seglib::filemap. +// 2. Added test for privately mapped files. +// 3. The test test_writeable was added for mapped files. +// 4. The test test_resizeable was added for mapped files. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +// Code generation bugs cause tests to fail with global optimization. +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("g", off) +#endif + +namespace boost { namespace iostreams { namespace test { + +bool test_writeable(mapped_file& mf) +{ + // Test writing + for (int i = 0; i < data_reps; ++i) { + memcpy(mf.data(), narrow_data(), chunk_size); + char buf[chunk_size]; + memcpy(buf, mf.const_data(), chunk_size); + if (strncmp(buf, narrow_data(), chunk_size) != 0) + return false; + memset(mf.data(), 0, chunk_size); + } + return true; +} + +bool test_resizeable(mapped_file& mf) +{ + // Test resizing + mapped_file::size_type size = mf.size(); + if (size == 0) + return false; + mf.resize(size/2); + if (mf.size() != size/2) + return false; + mf.resize(size); + if (mf.size() != size) + return false; + return true; +} + +} } } // End namespaces test, iostreams, boost. + +void mapped_file_test() +{ + using namespace boost::iostreams; + BOOST_MESSAGE("about to begin"); + + //--------------Reading from a mapped_file_source-------------------------// + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a stream based on a mapped_file_source, + // in chars. + boost::iostreams::test::test_file test1, test2; + boost::iostreams::stream first(test1.name()); + { + std::ifstream second( test2.name().c_str(), + BOOST_IOS::in | BOOST_IOS::binary ); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_streams_in_chars(first, second), + "failed reading from stream in chars" + ); + + BOOST_MESSAGE( + "done reading from stream in chars" + ); + } + first.close(); + + // Test reading from a stream based on a mapped_file_source, + // in chunks. (Also tests reopening the stream.) + first.open(mapped_file_source(test1.name())); + { + std::ifstream second( test2.name().c_str(), + BOOST_IOS::in | BOOST_IOS::binary ); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_streams_in_chunks(first, second), + "failed reading from stream in chunks" + ); + + BOOST_MESSAGE( + "done reading from stream in chunks" + ); + } + } + + //--------------Writing to a mapped_file_sink-----------------------------// + + { + // Test writing to a stream based on a mapped_file_sink, in + // chars. + boost::iostreams::test::uppercase_file first, second; // Will overwrite these. + boost::iostreams::test::test_file test; + + boost::iostreams::stream out; + out.open(mapped_file_sink(first.name())); + boost::iostreams::test::write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(first.name(), test.name()), + "failed writing to stream in chars" + ); + + BOOST_MESSAGE( + "done writing to stream in chars" + ); + + // Test writing to a stream based on a mapped_file_sink, in + // chunks. (Also tests reopening the stream.) + out.open(mapped_file_sink(second.name())); + boost::iostreams::test::write_data_in_chunks(out); + out.close(); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(second.name(), test.name()), + "failed writing to stream in chunks" + ); + + BOOST_MESSAGE( + "done writing to stream in chunks" + ); + } + + //--------------Writing to a newly created file---------------------------// + + { + // Test writing to a newly created mapped file. + boost::iostreams::test::temp_file first, second; + boost::iostreams::test::test_file test; + + mapped_file_params p(first.name()); + p.new_file_size = boost::iostreams::test::data_reps * boost::iostreams::test::data_length(); + boost::iostreams::stream out; + out.open(mapped_file_sink(p)); + boost::iostreams::test::write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(first.name(), test.name()), + "failed writing to newly created mapped file in chars" + ); + + + // Test writing to a newly created mapped file. + // (Also tests reopening the stream.) + p.path = second.name(); + out.open(mapped_file_sink(p)); + boost::iostreams::test::write_data_in_chunks(out); + out.close(); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(second.name(), test.name()), + "failed writing to newly created mapped file in chunks" + ); + } + + //--------------Writing to a pre-existing file---------------------------// + { + // Test for Bug #3953 - writing to a pre-existing mapped file. + boost::iostreams::test::test_file first, test; + + mapped_file_params p(first.name()); + p.new_file_size = boost::iostreams::test::data_reps * boost::iostreams::test::data_length(); + boost::iostreams::stream out; + out.open(mapped_file_sink(p)); + boost::iostreams::test::write_data_in_chars(out); + out.close(); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(first.name(), test.name()), + "failed writing to pre-existing mapped file in chars" + ); + } + + //--------------Random access with a mapped_file--------------------------// + + { + // Test reading, writing and seeking within a stream based on a + // mapped_file, in chars. + boost::iostreams::test::test_file test; + boost::iostreams::stream io; + io.open(mapped_file(test.name())); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_seekable_in_chars(io), + "failed seeking within stream in chars" + ); + + BOOST_MESSAGE( + "done seeking within stream in chars" + ); + + io.close(); + + // Test reading, writing and seeking within a stream based on a + // mapped_file, in chunks. (Also tests reopening the + // stream.) + io.open(mapped_file(test.name())); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_seekable_in_chunks(io), + "failed seeking within stream in chunks" + ); + + BOOST_MESSAGE( + "done seeking within stream in chunks" + ); + } + + //--------------Resizing a mapped_file------------------------------------// + + { + // Test resizing a mapped_file. + boost::iostreams::test::test_file test; + mapped_file mf; + mf.open(test.name()); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_resizeable(mf), + "failed resizing a mapped_file" + ); + + BOOST_MESSAGE( + "done resizing a mapped_file" + ); + } + + //--------------Random access with a private mapped_file------------------// + + { + // Use 2 copies of the file to compare later + boost::iostreams::test::test_file orig, copy; + + // Test reading and writing within a mapped_file. + // Since the file is privately mapped, it should remain + // unchanged after writing when opened in readonly mode. + mapped_file mf; + mf.open(orig.name(), mapped_file::priv); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_writeable(mf), + "failed seeking within private mapped_file" + ); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(orig.name(), copy.name()), + "failed writing to private mapped_file" + ); + + BOOST_MESSAGE( + "done seeking within private mapped_file" + ); + + mf.close(); + + // Test reopening the mapped file. + mf.open(orig.name(), mapped_file::priv); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_writeable(mf), + "failed reopening private mapped_file" + ); + BOOST_CHECK_MESSAGE( + boost::iostreams::test::compare_files(orig.name(), copy.name()), + "failed writing to reopened private mapped_file" + ); + + BOOST_MESSAGE( + "done reopening private mapped_file" + ); + } + + //-------------Check creating opening mapped_file with char*-------------// + + { + boost::iostreams::test::test_file orig; + char name[50]; + std::strcpy(name, orig.name().c_str()); + + mapped_file mf((char*) name); + + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_writeable(mf), + "failed seeking within private mapped_file" + ); + + mf.close(); + } + + //---------Check creating opening mapped_file with filesystem3 path------// + { + boost::iostreams::test::test_file orig; + + mapped_file mf(boost::filesystem::path(orig.name())); + + BOOST_CHECK_MESSAGE( + boost::iostreams::test::test_writeable(mf), + "failed seeking within private mapped_file" + ); + + mf.close(); + } +} + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("", on) +#endif + +boost::unit_test::test_suite* init_unit_test_suite(int, char* []) +{ + boost::unit_test::test_suite* test = BOOST_TEST_SUITE("mapped_file test"); + test->add(BOOST_TEST_CASE(&mapped_file_test)); + return test; +} diff --git a/libs/iostreams/test/newline_test.cpp b/libs/iostreams/test/newline_test.cpp new file mode 100644 index 0000000000..ab0c4dae0d --- /dev/null +++ b/libs/iostreams/test/newline_test.cpp @@ -0,0 +1,486 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace io = boost::iostreams; +using boost::unit_test::test_suite; + +const std::string posix = + "When I was one-and-twenty\n" + "I heard a wise man say,\n" + "'Give crowns and pounds and guineas\n" + "But not your heart away;\n" + "\n" + "Give pearls away and rubies\n" + "But keep your fancy free.'\n" + "But I was one-and-twenty,\n" + "No use to talk to me.\n" + "\n" + "When I was one-and-twenty\n" + "I heard him say again,\n" + "'The heart out of the bosom\n" + "Was never given in vain;\n" + "\n" + "'Tis paid with sighs a plenty\n" + "And sold for endless rue.'\n" + "And I am two-and-twenty,\n" + "And oh, 'tis true, 'tis true.\n"; + +const std::string dos = + "When I was one-and-twenty\r\n" + "I heard a wise man say,\r\n" + "'Give crowns and pounds and guineas\r\n" + "But not your heart away;\r\n" + "\r\n" + "Give pearls away and rubies\r\n" + "But keep your fancy free.'\r\n" + "But I was one-and-twenty,\r\n" + "No use to talk to me.\r\n" + "\r\n" + "When I was one-and-twenty\r\n" + "I heard him say again,\r\n" + "'The heart out of the bosom\r\n" + "Was never given in vain;\r\n" + "\r\n" + "'Tis paid with sighs a plenty\r\n" + "And sold for endless rue.'\r\n" + "And I am two-and-twenty,\r\n" + "And oh, 'tis true, 'tis true.\r\n"; + +const std::string mac = + "When I was one-and-twenty\r" + "I heard a wise man say,\r" + "'Give crowns and pounds and guineas\r" + "But not your heart away;\r" + "\r" + "Give pearls away and rubies\r" + "But keep your fancy free.'\r" + "But I was one-and-twenty,\r" + "No use to talk to me.\r" + "\r" + "When I was one-and-twenty\r" + "I heard him say again,\r" + "'The heart out of the bosom\r" + "Was never given in vain;\r" + "\r" + "'Tis paid with sighs a plenty\r" + "And sold for endless rue.'\r" + "And I am two-and-twenty,\r" + "And oh, 'tis true, 'tis true.\r"; + +const std::string no_final_newline = + "When I was one-and-twenty\n" + "I heard a wise man say,\n" + "'Give crowns and pounds and guineas\n" + "But not your heart away;\n" + "\n" + "Give pearls away and rubies\n" + "But keep your fancy free.'\n" + "But I was one-and-twenty,\n" + "No use to talk to me.\n" + "\n" + "When I was one-and-twenty\n" + "I heard him say again,\n" + "'The heart out of the bosom\n" + "Was never given in vain;\n" + "\n" + "'Tis paid with sighs a plenty\n" + "And sold for endless rue.'\n" + "And I am two-and-twenty,\n" + "And oh, 'tis true, 'tis true."; + +const std::string mixed = + "When I was one-and-twenty\n" + "I heard a wise man say,\r\n" + "'Give crowns and pounds and guineas\r" + "But not your heart away;\n" + "\r\n" + "Give pearls away and rubies\r" + "But keep your fancy free.'\n" + "But I was one-and-twenty,\r\n" + "No use to talk to me.\r" + "\r" + "When I was one-and-twenty\r\n" + "I heard him say again,\r" + "'The heart out of the bosom\n" + "Was never given in vain;\r\n" + "\r" + "'Tis paid with sighs a plenty\n" + "And sold for endless rue.'\r\n" + "And I am two-and-twenty,\r" + "And oh, 'tis true, 'tis true.\n"; + +struct string_source : boost::base_from_member, io::array_source { + typedef io::array_source base_type; + typedef boost::base_from_member pbase_type; + string_source(const std::string& src) + : pbase_type(src), base_type(member.data(), member.size()) + { } + + string_source(const string_source& src) + : pbase_type(src.member), base_type(member.data(), member.size()) + { } +}; + +void read_newline_filter() +{ + using namespace io; + + // Test converting to posix format. + + BOOST_CHECK(test_input_filter(newline_filter(newline::posix), posix, posix)); + BOOST_CHECK(test_input_filter(newline_filter(newline::posix), dos, posix)); + BOOST_CHECK(test_input_filter(newline_filter(newline::posix), mac, posix)); + BOOST_CHECK(test_input_filter(newline_filter(newline::posix), mixed, posix)); + + // Test converting to dos format. + + BOOST_CHECK(test_input_filter(newline_filter(newline::dos), posix, dos)); + BOOST_CHECK(test_input_filter(newline_filter(newline::dos), dos, dos)); + BOOST_CHECK(test_input_filter(newline_filter(newline::dos), mac, dos)); + BOOST_CHECK(test_input_filter(newline_filter(newline::dos), mixed, dos)); + + // Test converting to mac format. + + BOOST_CHECK(test_input_filter(newline_filter(newline::mac), posix, mac)); + BOOST_CHECK(test_input_filter(newline_filter(newline::mac), dos, mac)); + BOOST_CHECK(test_input_filter(newline_filter(newline::mac), mac, mac)); + BOOST_CHECK(test_input_filter(newline_filter(newline::mac), mixed, mac)); +} + +// Verify that a filter works as expected with both a non-blocking sink +// and a normal output stream. +// +// test_output_filter only tests for a non-blocking sink. +// TODO: Other tests should probably test with an output stream. + +template +bool my_test_output_filter(Filter filter, + const std::string& input, + const std::string& output) +{ + const std::streamsize default_increment = 5; + + for ( int inc = default_increment; + inc < default_increment * 40; + inc += default_increment ) + { + io::array_source src(input.data(), input.data() + input.size()); + + std::ostringstream stream; + io::copy(src, compose(filter, stream)); + if (stream.str() != output ) + return false; + + } + return test_output_filter(filter, input, output); +} + +void write_newline_filter() +{ + using namespace io; + + // Test converting to posix format. + + BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), posix, posix)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), dos, posix)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), mac, posix)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), mixed, posix)); + + // Test converting to dos format. + + BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), posix, dos)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), dos, dos)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), mac, dos)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), mixed, dos)); + + // Test converting to mac format. + + BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), posix, mac)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), dos, mac)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), mac, mac)); + BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), mixed, mac)); +} + +void test_input_against_flags(int flags, const std::string& input, bool read) +{ + if (read) { + io::copy( + io::compose( + io::newline_checker(flags), + string_source(input) + ), + io::null_sink() + ); + } else { + io::copy( + string_source(input), + io::compose(io::newline_checker(flags), io::null_sink()) + ); + } +} + +void read_newline_checker() +{ + io::filtering_istream in; + io::newline_checker* checker = 0; + + // Verify properties of ::posix. + + in.push(io::newline_checker(io::newline::posix)); + in.push(string_source(::posix)); + BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink())); + checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker); + BOOST_CHECK(checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + in.pop(); // pop checker. + + // Verify properties of ::dos. + + in.push(io::newline_checker(io::newline::dos)); + in.push(string_source(::dos)); + try { + io::copy(in, io::null_sink()); + } catch (io::newline_error&) { + BOOST_CHECK_MESSAGE( + false, "failed checking for dos line endings" + ); + } + checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + in.pop(); // pop checker. + + // Verify properties of ::mac. + + in.push(io::newline_checker(io::newline::mac)); + in.push(string_source(::mac)); + BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink())); + checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + in.pop(); // pop checker. + + // Verify properties of no_final_newline. + + in.push(io::newline_checker(io::newline::posix)); + in.push(string_source(::no_final_newline)); + BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink())); + checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker); + BOOST_CHECK(checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(!checker->has_final_newline()); + in.pop(); // pop checker. + + // Verify properties of mixed. + + in.push(io::newline_checker()); + in.push(string_source(::mixed)); + BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink())); + checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(checker->is_mixed_posix()); + BOOST_CHECK(checker->is_mixed_dos()); + BOOST_CHECK(checker->is_mixed_mac()); + BOOST_CHECK(checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + in.pop(); // pop checker. + + // Verify exceptions when input does not satisfy target conditions. + + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::posix, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::posix, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::dos, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::dos, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::mac, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::mac, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::final_newline, ::no_final_newline, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::mixed, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::mixed, true), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::mixed, true), + io::newline_error + ) +} + +void write_newline_checker() +{ + io::filtering_ostream out; + io::newline_checker* checker = 0; + + // Verify properties of ::posix. + + out.push(io::newline_checker(io::newline::posix)); + out.push(io::null_sink()); + BOOST_CHECK_NO_THROW(io::copy(string_source(::posix), out)) + checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker); + BOOST_CHECK(checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + out.pop(); // pop checker. + + // Verify properties of ::dos. + + out.push(io::newline_checker(io::newline::dos)); + out.push(io::null_sink()); + BOOST_CHECK_NO_THROW(io::copy(string_source(::dos), out)) + checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + out.pop(); // pop checker. + + // Verify properties of ::mac. + + out.push(io::newline_checker(io::newline::mac)); + out.push(io::null_sink()); + BOOST_CHECK_NO_THROW(io::copy(string_source(::mac), out)) + checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + out.pop(); // pop checker. + + // Verify properties of no_final_newline. + + out.push(io::newline_checker(io::newline::posix)); + out.push(io::null_sink()); + BOOST_CHECK_NO_THROW(io::copy(string_source(::no_final_newline), out)) + checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker); + BOOST_CHECK(checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(!checker->is_mixed()); + BOOST_CHECK(!checker->has_final_newline()); + out.pop(); // pop checker. + + // Verify properties of mixed. + + out.push(io::newline_checker()); + out.push(io::null_sink()); + BOOST_CHECK_NO_THROW(io::copy(string_source(::mixed), out)) + checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker); + BOOST_CHECK(!checker->is_posix()); + BOOST_CHECK(!checker->is_dos()); + BOOST_CHECK(!checker->is_mac()); + BOOST_CHECK(checker->is_mixed_posix()); + BOOST_CHECK(checker->is_mixed_dos()); + BOOST_CHECK(checker->is_mixed_mac()); + BOOST_CHECK(checker->is_mixed()); + BOOST_CHECK(checker->has_final_newline()); + out.pop(); // pop checker. + + // Verify exceptions when input does not satisfy target conditions. + + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::posix, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::posix, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::dos, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::dos, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::mac, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::mac, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::final_newline, ::no_final_newline, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::posix, ::mixed, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::dos, ::mixed, false), + io::newline_error + ) + BOOST_CHECK_THROW( + test_input_against_flags(io::newline::mac, ::mixed, false), + io::newline_error + ) +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("newline_filter test"); + test->add(BOOST_TEST_CASE(&read_newline_filter)); + test->add(BOOST_TEST_CASE(&write_newline_filter)); + test->add(BOOST_TEST_CASE(&read_newline_checker)); + test->add(BOOST_TEST_CASE(&write_newline_checker)); + return test; +} diff --git a/libs/iostreams/test/null_test.cpp b/libs/iostreams/test/null_test.cpp new file mode 100644 index 0000000000..e90d18f832 --- /dev/null +++ b/libs/iostreams/test/null_test.cpp @@ -0,0 +1,44 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +void read_null_source() +{ + stream in; + in.open(null_source()); + in.get(); + BOOST_CHECK(in.eof()); +} + +void write_null_sink() +{ + stream out; + out.open(null_sink()); + write_data_in_chunks(out); + BOOST_CHECK(out.good()); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("null test"); + test->add(BOOST_TEST_CASE(&read_null_source)); + test->add(BOOST_TEST_CASE(&write_null_sink)); + return test; +} diff --git a/libs/iostreams/test/operation_sequence_test.cpp b/libs/iostreams/test/operation_sequence_test.cpp new file mode 100644 index 0000000000..b03b8e0707 --- /dev/null +++ b/libs/iostreams/test/operation_sequence_test.cpp @@ -0,0 +1,268 @@ +/* + * 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. + * + * Tests the facilities defined in the header + * libs/iostreams/test/detail/operation_sequence.hpp + * + * File: libs/iostreams/test/operation_sequence_test.cpp + * Date: Mon Dec 10 18:58:19 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + */ + +#include +#include +#include +#include "detail/operation_sequence.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + + // Infrastructure for checking that operations are + // executed in the correct order + +void operation_sequence_test() +{ + // Test creating a duplicate operation + { + operation_sequence seq; + operation op = seq.new_operation(1); + BOOST_CHECK_THROW(seq.new_operation(1), runtime_error); + } + + // Test reusing an operation id after first operation is destroyed + { + operation_sequence seq; + seq.new_operation(1); + BOOST_CHECK_NO_THROW(seq.new_operation(1)); + } + + // Test creating operations with illegal error codes + { + operation_sequence seq; + BOOST_CHECK_THROW(seq.new_operation(1, -100), runtime_error); + BOOST_CHECK_THROW( + seq.new_operation(1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR + 1), + runtime_error + ); + } + + // Test two successful operations executed out of order + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op2 = seq.new_operation(2); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op2.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op1.execute()); + BOOST_CHECK(seq.is_failure()); + } + + // Test executing an operation twice without resetting the sequence + { + operation_sequence seq; + operation op = seq.new_operation(1); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op.execute()); + BOOST_CHECK(seq.is_success()); + BOOST_CHECK_NO_THROW(op.execute()); + BOOST_CHECK(seq.is_failure()); + } + + // Test creating an operation after operation execution has commenced + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op2 = seq.new_operation(2); + operation op3; + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op1.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op3 = seq.new_operation(3), runtime_error); + BOOST_CHECK_NO_THROW(op2.execute()); + BOOST_CHECK(seq.is_success()); + } + + // Test three successful operations with consecutive ids, executed in order + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op2 = seq.new_operation(2); + operation op3 = seq.new_operation(3); + + // First pass + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + + // Second pass + seq.reset(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + } + + // Test three successful operations with non-consecutive ids, + // executed in order + { + operation_sequence seq; + operation op2 = seq.new_operation(2); + operation op3 = seq.new_operation(101); + operation op1 = seq.new_operation(-43); + + // First pass + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + + // Second pass + seq.reset(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + } + + // Test checking for success after one of three operations + // has been destroyed + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op3 = seq.new_operation(3); + + { + operation op2 = seq.new_operation(2); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + } + BOOST_CHECK(seq.is_success()); + } + + // Test executing an operation sequence twice, with one of the + // operations replaced with a new operation with the same id + // in the second pass + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op3 = seq.new_operation(3); + + // First pass + { + operation op2 = seq.new_operation(2); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + } + + // Second pass + seq.reset(); + { + operation op2 = seq.new_operation(2); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op1.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op2.execute(); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + op3.execute(); + BOOST_CHECK(seq.is_success()); + } + } + + // Test three operations executed in order, the first of which throws + { + operation_sequence seq; + operation op1 = seq.new_operation(1, 1); + operation op2 = seq.new_operation(2); + operation op3 = seq.new_operation(3); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op1.execute(), operation_error<1>); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op2.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op3.execute()); + BOOST_CHECK(seq.is_success()); + } + + // Test three operations executed in order, the second of which throws + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op2 = seq.new_operation(2, 2); + operation op3 = seq.new_operation(3); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op1.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op2.execute(), operation_error<2>); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op3.execute()); + BOOST_CHECK(seq.is_success()); + } + + // Test three operations executed in order, the third of which throws + { + operation_sequence seq; + operation op1 = seq.new_operation(1); + operation op2 = seq.new_operation(2); + operation op3 = seq.new_operation(3, 3); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op1.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op2.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op3.execute(), operation_error<3>); + BOOST_CHECK(seq.is_success()); + } + + // Test three operations executed in order, the first and + // third of which throw + { + operation_sequence seq; + operation op1 = seq.new_operation(1, 1); + operation op2 = seq.new_operation(2); + operation op3 = seq.new_operation(3, 3); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op1.execute(), operation_error<1>); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_NO_THROW(op2.execute()); + BOOST_CHECK(!seq.is_failure() && !seq.is_success()); + BOOST_CHECK_THROW(op3.execute(), operation_error<3>); + BOOST_CHECK(seq.is_success()); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("execute test"); + test->add(BOOST_TEST_CASE(&operation_sequence_test)); + return test; +} diff --git a/libs/iostreams/test/path_test.cpp b/libs/iostreams/test/path_test.cpp new file mode 100644 index 0000000000..313c851bc3 --- /dev/null +++ b/libs/iostreams/test/path_test.cpp @@ -0,0 +1,25 @@ +// (C) Copyright Daniel James 2011. +// 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. + +#include +#include + +#include +#include + +void path_test() +{ + boost::filesystem::path orig("a/b"); + boost::iostreams::detail::path p(orig); + p = orig; +} + +boost::unit_test::test_suite* init_unit_test_suite(int, char* []) +{ + boost::unit_test::test_suite* test = BOOST_TEST_SUITE("mapped_file test"); + test->add(BOOST_TEST_CASE(&path_test)); + return test; +} diff --git a/libs/iostreams/test/pipeline_test.cpp b/libs/iostreams/test/pipeline_test.cpp new file mode 100644 index 0000000000..2f621c7cf4 --- /dev/null +++ b/libs/iostreams/test/pipeline_test.cpp @@ -0,0 +1,90 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using boost::unit_test::test_suite; + +void pipeline_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + { + test_file src; + filtering_istream + in1( toupper_filter() | + file_source(src.name()) ); + filtering_istream + in2( toupper_filter() | + toupper_filter() | + file_source(src.name()) ); + filtering_istream + in3( toupper_filter() | + toupper_filter() | + toupper_filter() | + file_source(src.name()) ); + filtering_istream + in4( toupper_filter() | + toupper_filter() | + toupper_filter() | + toupper_filter() | + file_source(src.name()) ); + BOOST_CHECK(in1.size() == 2); + BOOST_CHECK(in2.size() == 3); + BOOST_CHECK(in3.size() == 4); + BOOST_CHECK(in4.size() == 5); + } + + { + test_file src; + uppercase_file upper; + filtering_istream + first( toupper_filter() | + toupper_multichar_filter() | + file_source(src.name(), in_mode) ); + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filtering_istream in chunks with a " + "multichar input filter" + ); + } + + { + temp_file dest; + lowercase_file lower; + filtering_ostream + out( tolower_filter() | + tolower_multichar_filter() | + file_sink(dest.name(), out_mode) ); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chunks with a " + "multichar output filter with no buffer" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("pipeline test"); + test->add(BOOST_TEST_CASE(&pipeline_test)); + return test; +} diff --git a/libs/iostreams/test/putback_test.hpp b/libs/iostreams/test/putback_test.hpp new file mode 100644 index 0000000000..05b4f5addb --- /dev/null +++ b/libs/iostreams/test/putback_test.hpp @@ -0,0 +1,167 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_PUTBACK_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_PUTBACK_HPP_INCLUDED + +#include +#include +#include +#include "detail/constants.hpp" +#include "detail/temp_file.hpp" + +using boost::iostreams::test::chunk_size; + +bool putback_test_one(std::istream& is) +{ + try { + do { + char buf[chunk_size]; + is.read(buf, chunk_size); + if (is.gcount() < static_cast(chunk_size)) + break; + is.putback('a'); + if (is.get() != 'a') + return false; + } while (!is.eof()); + return true; + } catch (std::exception&) { return false; } +} + +bool putback_test_two(std::istream& is) +{ + try { + do { + char buf[chunk_size]; + is.read(buf, chunk_size); + if (is.gcount() < static_cast(chunk_size)) + break; + is.putback('a'); + is.putback('b'); + is.putback('c'); + is.putback('d'); + if ( is.get() != 'd' || is.get() != 'c' || + is.get() != 'b' || is.get() != 'a' ) + { + return false; + } + } while (!is.eof()); + return true; + } catch (std::exception&) { return false; } +} + +template +bool putback_test_three(Source& src) +{ + try { + while (true) { + char buf[chunk_size]; + if (boost::iostreams::read(src, buf, chunk_size) < chunk_size) + break; + boost::iostreams::putback(src, 'a'); + if (boost::iostreams::get(src) != 'a') + return false; + } + return true; + } catch (std::exception&) { return false; } +} + +template +bool putback_test_four(Source& src) +{ + try { + while (true) { + char buf[chunk_size]; + if (boost::iostreams::read(src, buf, chunk_size) < chunk_size) + break; + boost::iostreams::putback(src, 'a'); + boost::iostreams::putback(src, 'b'); + boost::iostreams::putback(src, 'c'); + boost::iostreams::putback(src, 'd'); + if ( boost::iostreams::get(src) != 'd' || + boost::iostreams::get(src) != 'c' || + boost::iostreams::get(src) != 'b' || + boost::iostreams::get(src) != 'a' ) + { + return false; + } + } + return true; + } catch (std::exception&) { return false; } +} + +void putback_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + filtering_istream is; + is.set_device_buffer_size(0); + is.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_one(is), + "failed putting back to unbuffered filtering_istream" + ); + } + + { + filtering_istream is; + is.set_pback_size(4); + is.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_two(is), + "failed putting back to buffered filtering_istream" + ); + } + + { + filtering_istream is; + is.set_device_buffer_size(0); + is.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_three(is), + "failed putting back to unbuffered filtering_istream" + ); + } + + { + filtering_istream is; + is.set_pback_size(4); + is.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_four(is), + "failed putting back to buffered filtering_istream" + ); + } + + { + filtering_istreambuf sb; + sb.set_device_buffer_size(0); + sb.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_three(sb), + "failed putting back to unbuffered filtering_istream" + ); + } + + { + filtering_istreambuf sb; + sb.set_pback_size(4); + sb.push(file_source(test.name())); + BOOST_CHECK_MESSAGE( + putback_test_four(sb), + "failed putting back to buffered filtering_istream" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_PUTBACK_HPP_INCLUDED diff --git a/libs/iostreams/test/read_bidir_filter_test.hpp b/libs/iostreams/test/read_bidir_filter_test.hpp new file mode 100644 index 0000000000..b30a0cf00b --- /dev/null +++ b/libs/iostreams/test/read_bidir_filter_test.hpp @@ -0,0 +1,131 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_FILTER_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_FILTER_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_bidirectional_filter_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + uppercase_file upper; + + //{ + // test_file src; + // temp_file dest; // Dummy. + // filtering_stream first; + // first.push(combine(toupper_filter(), tolower_filter())); + // first.push( + // combine(file_source(src.name()), file_sink(dest.name())) + // ); + // ifstream second(upper.name().c_str()); + // BOOST_CHECK_MESSAGE( + // compare_streams_in_chars(first, second), + // "failed reading from filtering_stream in chars with an " + // "input filter" + // ); + //} + + { + test_file src; + temp_file dest; // Dummy. + filtering_stream first; + first.push(combine(toupper_filter(), tolower_filter())); + first.push( + combine(file_source(src.name()), file_sink(dest.name())) + ); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream in chunks with an " + "input filter" + ); + } + + //{ + // test_file src; + // temp_file dest; // Dummy. + // filtering_stream first( + // combine(toupper_multichar_filter(), tolower_filter()), 0 + // ); + // first.push( + // combine(file_source(src.name()), file_sink(dest.name())) + // ); + // ifstream second(upper.name().c_str()); + // BOOST_CHECK_MESSAGE( + // compare_streams_in_chars(first, second), + // "failed reading from filtering_stream in chars with " + // "a multichar input filter with no buffer" + // ); + //} + + //{ + // test_file src; + // temp_file dest; // Dummy. + // filtering_stream first( + // combine(toupper_multichar_filter(), tolower_filter()), 0 + // ); + // first.push( + // combine(file_source(src.name()), file_sink(dest.name())) + // ); + // ifstream second(upper.name().c_str()); + // BOOST_CHECK_MESSAGE( + // compare_streams_in_chunks(first, second), + // "failed reading from filtering_stream in chunks " + // "with a multichar input filter with no buffer" + // ); + //} + + //{ + // test_file src; + // temp_file dest; // Dummy. + // filtering_stream first( + // combine(toupper_multichar_filter(), tolower_filter()) + // ); + // first.push( + // combine(file_source(src.name()), file_sink(dest.name())) + // ); + // ifstream second(upper.name().c_str()); + // BOOST_CHECK_MESSAGE( + // compare_streams_in_chars(first, second), + // "failed reading from filtering_stream in chars with a " + // "multichar input filter" + // ); + //} + + //{ + // test_file src; + // temp_file dest; // Dummy. + // filtering_stream first( + // combine(toupper_multichar_filter(), tolower_filter()) + // ); + // first.push( + // combine(file_source(src.name()), file_sink(dest.name())) + // ); + // ifstream second(upper.name().c_str()); + // BOOST_CHECK_MESSAGE( + // compare_streams_in_chunks(first, second), + // "failed reading from filtering_stream in chunks " + // "with a multichar input filter" + // ); + //} +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_FILTER_HPP_INCLUDED diff --git a/libs/iostreams/test/read_bidir_streambuf_test.hpp b/libs/iostreams/test/read_bidir_streambuf_test.hpp new file mode 100644 index 0000000000..4a14cad248 --- /dev/null +++ b/libs/iostreams/test/read_bidir_streambuf_test.hpp @@ -0,0 +1,77 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_bidirectional_streambuf_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test1; + test_file test2; + + { + filebuf fb; + fb.open(test1.name().c_str(), BOOST_IOS::in); + filtering_stream first(fb, 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream based on a" + "streambuf in chars with no buffer" + ); + } + + { + filebuf fb; + fb.open(test1.name().c_str(), BOOST_IOS::in); + filtering_stream first(fb, 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream based on a" + "streambuf in chunks with no buffer" + ); + } + + { + filebuf fb; + fb.open(test1.name().c_str(), BOOST_IOS::in); + filtering_stream first(fb); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream based on a" + "streambuf in chars with large buffer" + ); + } + + { + filebuf fb; + fb.open(test1.name().c_str(), BOOST_IOS::in); + filtering_stream first(fb); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream based on a" + "streambuf in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED diff --git a/libs/iostreams/test/read_bidir_test.hpp b/libs/iostreams/test/read_bidir_test.hpp new file mode 100644 index 0000000000..8351bd16e0 --- /dev/null +++ b/libs/iostreams/test/read_bidir_test.hpp @@ -0,0 +1,85 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_bidirectional_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + test_file src; + temp_file dest; // Dummy. + filtering_stream first( + combine(file_source(src.name()), file_sink(dest.name())), 0 + ); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream" + "in chars with no buffer" + ); + } + + { + test_file src; + temp_file dest; // Dummy. + filtering_stream first( + combine(file_source(src.name()), file_sink(dest.name())), 0 + ); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream" + "in chunks with no buffer" + ); + } + + { + test_file src; + temp_file dest; // Dummy. + filtering_stream first( + combine(file_source(src.name()), file_sink(dest.name())) + ); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream" + "in chars with large buffer" + ); + } + + { + test_file src; + temp_file dest; // Dummy. + filtering_stream first( + combine(file_source(src.name()), file_sink(dest.name())) + ); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream" + "in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_BIDIRECTIONAL_HPP_INCLUDED diff --git a/libs/iostreams/test/read_input_filter_test.hpp b/libs/iostreams/test/read_input_filter_test.hpp new file mode 100644 index 0000000000..7057546231 --- /dev/null +++ b/libs/iostreams/test/read_input_filter_test.hpp @@ -0,0 +1,105 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_FILTER_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_INPUT_FILTER_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_input_filter_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + uppercase_file upper; + + { + filtering_istream first; + first.push(toupper_filter()); + first.push(file_source(test.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a filtering_istream in chars with an " + "input filter" + ); + } + + { + filtering_istream first; + first.push(toupper_filter()); + first.push(file_source(test.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filtering_istream in chunks with an " + "input filter" + ); + } + + { + filtering_istream first; + first.push(toupper_multichar_filter(), 0); + first.push(file_source(test.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a filtering_istream in chars with a " + "multichar input filter with no buffer" + ); + } + + { + filtering_istream first; + first.push(toupper_multichar_filter(), 0); + first.push(file_source(test.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filtering_istream in chunks with a " + "multichar input filter with no buffer" + ); + } + + { + test_file src; + filtering_istream first; + first.push(toupper_multichar_filter()); + first.push(file_source(src.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a filtering_istream in chars with a " + "multichar input filter" + ); + } + + { + test_file src; + filtering_istream first; + first.push(toupper_multichar_filter()); + first.push(file_source(src.name())); + ifstream second(upper.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filtering_istream in chunks with a " + "multichar input filter" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_FILTER_HPP_INCLUDED diff --git a/libs/iostreams/test/read_input_istream_test.hpp b/libs/iostreams/test/read_input_istream_test.hpp new file mode 100644 index 0000000000..fa1552253f --- /dev/null +++ b/libs/iostreams/test/read_input_istream_test.hpp @@ -0,0 +1,76 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_ISTREAM_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_INPUT_ISTREAM_HPP_INCLUDED + +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_input_istream_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + test_file test2; + + { + test_file test2; + ifstream src(test2.name().c_str()); + filtering_istream first(src, 0); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_istream based on an istream" + "in chars with no buffer" + ); + } + + { + test_file test2; + ifstream src(test2.name().c_str()); + filtering_istream first(src, 0); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_istream based on an istream" + "in chunks with no buffer" + ); + } + + { + test_file test2; + ifstream src(test2.name().c_str()); + filtering_istream first(src); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_istream based on an istream" + "in chars with large buffer" + ); + } + + { + test_file test2; + ifstream src(test2.name().c_str()); + filtering_istream first(src); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_istream based on an istream" + "in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_ISTREAM_HPP_INCLUDED diff --git a/libs/iostreams/test/read_input_seq_test.hpp b/libs/iostreams/test/read_input_seq_test.hpp new file mode 100644 index 0000000000..f26f833de5 --- /dev/null +++ b/libs/iostreams/test/read_input_seq_test.hpp @@ -0,0 +1,70 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_INPUT_SEQUENCE_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_input_sequence_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file file; + test_sequence<> seq; + + { + filtering_stream first(make_iterator_range(seq), 0); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from range_adapter " + "in chars with no buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq), 0); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from range_adapter " + "in chars with no buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq)); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from range_adapter " + "in chars with large buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq)); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from range_adapter " + "in chars with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/read_input_test.hpp b/libs/iostreams/test/read_input_test.hpp new file mode 100644 index 0000000000..e8e0015beb --- /dev/null +++ b/libs/iostreams/test/read_input_test.hpp @@ -0,0 +1,65 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_INPUT_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_input_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test1; + test_file test2; + + { + filtering_istream first(file_source(test1.name()), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_istream in chars with no buffer" + ); + } + + { + filtering_istream first(file_source(test1.name()), 0); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_istream in chunks with no buffer" + ); + } + + { + filtering_istream first(file_source(test1.name())); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_istream in chars with buffer" + ); + } + + { + filtering_istream first(file_source(test1.name())); + ifstream second(test2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_istream in chunks with buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_INPUT_HPP_INCLUDED diff --git a/libs/iostreams/test/read_seekable_seq_test.hpp b/libs/iostreams/test/read_seekable_seq_test.hpp new file mode 100644 index 0000000000..185d15d8dc --- /dev/null +++ b/libs/iostreams/test/read_seekable_seq_test.hpp @@ -0,0 +1,71 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_SEEKABLE_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_SEEKABLE_SEQUENCE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_seekable_sequence_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file file; + test_sequence<> seq; + + { + filtering_stream first(make_iterator_range(seq), 0); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream based on a" + "sequence in chars with no buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq), 0); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream based on a" + "sequence in chunks with no buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq)); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream based on a" + "sequence in chars with large buffer" + ); + } + + { + filtering_stream first(make_iterator_range(seq)); + ifstream second(file.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream based on a" + "sequence in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_SEEKABLE_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/read_seekable_test.hpp b/libs/iostreams/test/read_seekable_test.hpp new file mode 100644 index 0000000000..f059f61db8 --- /dev/null +++ b/libs/iostreams/test/read_seekable_test.hpp @@ -0,0 +1,69 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_READ_SEEKABLE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_READ_SEEKABLE_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void read_seekable_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test1; + test_file test2; + + { + filtering_stream first(file(test1.name(), in_mode), 0); + ifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream" + "in chars with no buffer" + ); + } + + { + filtering_stream first(file(test1.name(), in_mode), 0); + ifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream" + "in chars with no buffer" + ); + } + + { + filtering_stream first(file(test1.name(), in_mode)); + ifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from filtering_stream" + "in chars with large buffer" + ); + } + + { + filtering_stream first(file(test1.name(), in_mode)); + ifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from filtering_stream" + "in chars with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_READ_SEEKABLE_HPP_INCLUDED diff --git a/libs/iostreams/test/regex_filter_test.cpp b/libs/iostreams/test/regex_filter_test.cpp new file mode 100644 index 0000000000..8fd02d67f8 --- /dev/null +++ b/libs/iostreams/test/regex_filter_test.cpp @@ -0,0 +1,329 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#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; + +struct replace_lower { + std::string operator() (const boost::match_results&) + { return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } +#ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS + std::wstring operator() (const boost::match_results&) + { return L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } +#endif +}; + +void regex_filter_test() +{ + // Note: Given the basic stream and filter tests, two regex tests + // are probably sufficient: reading with a filter based on a function, + // and writing with a filter based on a format string. + + test_file test; + uppercase_file upper; + + boost::regex match_lower("[a-z]+"); + std::string fmt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter based on a function in chars. + filtering_istream + first(boost::iostreams::regex_filter(match_lower, replace_lower())); + first.push(file_source(test.name(), in_mode)); + { + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from function-based regex_filter in chars" + ); + } + first.pop(); + + // Test reading from a regex filter based on a function in chunks. + // (Also tests reusing the regex filter.) + first.push(file_source(test.name(), in_mode)); + { + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from function-based regex_filter in chunks" + ); + } + } + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter based on a format string in chars. + filtering_istream + first(boost::iostreams::regex_filter(match_lower, fmt)); + first.push(file_source(test.name(), in_mode)); + { + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from format-string-based regex_filter in chars" + ); + } + first.pop(); + + // Test reading from a regex filter based on a format string in chunks. + // (Also tests reusing the regex filter.) + first.push(file_source(test.name(), in_mode)); + { + ifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from format-string-based regex_filter in chunks" + ); + } + } + + { + test_file dest1; + test_file dest2; + + // Test writing to a regex filter based on a function in chars. + filtering_ostream + out(boost::iostreams::regex_filter(match_lower, replace_lower())); + out.push(file_sink(dest1.name(), out_mode)); + write_data_in_chars(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), upper.name()), + "failed writing to function-based regex_filter in chars" + ); + + // Test writing to a regex filter based on a function in chunks. + // (Also tests reusing the regex filter.) + out.push(file_sink(dest2.name(), out_mode)); + write_data_in_chunks(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest2.name(), upper.name()), + "failed writing to function-based regex_filter in chunks" + ); + } + + { + test_file dest1; + test_file dest2; + + // Test writing to a regex filter based on a format string in chars. + filtering_ostream + out(boost::iostreams::regex_filter(match_lower, fmt)); + out.push(file_sink(dest1.name(), out_mode)); + write_data_in_chars(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), upper.name()), + "failed writing to format-string-based regex_filter in chars" + ); + + // Test writing to a regex filter based on a format string in chunks. + // (Also tests reusing the regex filter.) + out.push(file_sink(dest2.name(), out_mode)); + write_data_in_chunks(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest2.name(), upper.name()), + "failed writing to format-string-based regex_filter in chunks" + ); + } + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter with no matches; this checks that + // Ticket #1139 is fixed + boost::regex match_xxx("xxx"); + test_file test2; + filtering_istream + first(boost::iostreams::regex_filter(match_xxx, replace_lower())); + first.push(file_source(test.name(), in_mode)); + { + ifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a regex filter with no matches" + ); + } + } +} + +#ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS + +void wregex_filter_test() +{ + // Note: Given the basic stream and filter tests, two regex tests + // are probably sufficient: reading with a filter based on a function, + // and writing with a filter based on a format string. + + test_file test; + uppercase_file upper; + + boost::wregex match_lower(L"[a-z]+"); + std::wstring fmt = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter based on a function in chars. + filtering_wistream + first(boost::iostreams::wregex_filter(match_lower, replace_lower())); + first.push(wfile_source(test.name(), in_mode)); + { + wifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from function-based regex_filter in chars" + ); + } + first.pop(); + + // Test reading from a regex filter based on a function in chunks. + // (Also tests reusing the regex filter.) + first.push(wfile_source(test.name(), in_mode)); + { + wifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from function-based regex_filter in chunks" + ); + } + } + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter based on a format string in chars. + filtering_wistream + first(boost::iostreams::wregex_filter(match_lower, fmt)); + first.push(wfile_source(test.name(), in_mode)); + { + wifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from format-string-based regex_filter in chars" + ); + } + first.pop(); + + // Test reading from a regex filter based on a format string in chunks. + // (Also tests reusing the regex filter.) + first.push(wfile_source(test.name(), in_mode)); + { + wifstream second(upper.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from format-string-based regex_filter in chunks" + ); + } + } + + { + test_file dest1; + test_file dest2; + + // Test writing to a regex filter based on a function in chars. + filtering_wostream + out(boost::iostreams::wregex_filter(match_lower, replace_lower())); + out.push(wfile_sink(dest1.name(), out_mode)); + write_data_in_chars(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), upper.name()), + "failed writing to function-based regex_filter in chars" + ); + + // Test writing to a regex filter based on a function in chunks. + // (Also tests reusing the regex filter.) + out.push(wfile_sink(dest2.name(), out_mode)); + write_data_in_chunks(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest2.name(), upper.name()), + "failed writing to function-based regex_filter in chunks" + ); + } + + { + test_file dest1; + test_file dest2; + + // Test writing to a regex filter based on a format string in chars. + filtering_wostream + out(boost::iostreams::wregex_filter(match_lower, fmt)); + out.push(wfile_sink(dest1.name(), out_mode)); + write_data_in_chars(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), upper.name()), + "failed writing to format-string-based regex_filter in chars" + ); + + // Test writing to a regex filter based on a format string in chunks. + // (Also tests reusing the regex filter.) + out.push(wfile_sink(dest2.name(), out_mode)); + write_data_in_chunks(out); + out.pop(); + BOOST_CHECK_MESSAGE( + compare_files(dest2.name(), upper.name()), + "failed writing to format-string-based regex_filter in chunks" + ); + } + + { + // Note: the ifstream second is placed in a nested scope because + // closing and reopening a single ifstream failed for CW 9.4 on Windows. + + // Test reading from a regex filter with no matches; this checks that + // Ticket #1139 is fixed + boost::wregex match_xxx(L"xxx"); + test_file test2; + filtering_wistream + first(boost::iostreams::wregex_filter(match_xxx, replace_lower())); + first.push(wfile_source(test.name(), in_mode)); + { + wifstream second(test2.name().c_str(), in_mode); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a regex filter with no matches" + ); + } + } +} + +#endif + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("regex_filter test"); + test->add(BOOST_TEST_CASE(®ex_filter_test)); +#ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS + test->add(BOOST_TEST_CASE(&wregex_filter_test)); +#endif + return test; +} diff --git a/libs/iostreams/test/restrict_test.cpp b/libs/iostreams/test/restrict_test.cpp new file mode 100644 index 0000000000..3abf21555a --- /dev/null +++ b/libs/iostreams/test/restrict_test.cpp @@ -0,0 +1,690 @@ +// (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_RESTRICT with BOOST_IOSTREAMS_RESTRICT here, since that +// would interfere with the oepration of the header +// +#include + +#if defined(BOOST_RESTRICT_USE_SLICE) +# include +# define BOOST_RESTRICT slice +#else +# include +# define BOOST_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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(); + array ar(&src[0], &src[0] + src.size()); + filtering_stream io(BOOST_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; + array ar(&src[0], &src[0] + src.size()); + filtering_stream io(BOOST_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_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_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_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_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_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_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_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_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_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_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_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; +} diff --git a/libs/iostreams/test/seek_test.hpp b/libs/iostreams/test/seek_test.hpp new file mode 100644 index 0000000000..68c0aeaf09 --- /dev/null +++ b/libs/iostreams/test/seek_test.hpp @@ -0,0 +1,51 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_SEEK_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_SEEK_HPP_INCLUDED + + +#include // BOOST_MSVC, make sure size_t is in std. +#include // std::size_t. +#include +#include +#include +#include +#include "../example/container_device.hpp" // We use container_device instead +#include "detail/verification.hpp" // of make_iterator_range to + // reduce dependence on Boost.Range + +void seek_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::example; + using namespace boost::iostreams::test; + + { + string test(data_reps * data_length(), '\0'); + filtering_stream io; + io.push(container_device(test)); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within a filtering_stream, in chars" + ); + } + + { + string test(data_reps * data_length(), '\0'); + filtering_stream io; + io.push(container_device(test)); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within a filtering_stream, in chunks" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_SEEK_HPP_INCLUDED diff --git a/libs/iostreams/test/seekable_file_test.cpp b/libs/iostreams/test/seekable_file_test.cpp new file mode 100644 index 0000000000..738bc1bac2 --- /dev/null +++ b/libs/iostreams/test/seekable_file_test.cpp @@ -0,0 +1,56 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +void seekable_file_test() +{ + { + temp_file temp; + file f( temp.name(), + BOOST_IOS::in | BOOST_IOS::out | + BOOST_IOS::trunc | BOOST_IOS::binary); + filtering_stream io(f); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within a file, in chars" + ); + } + + { + temp_file temp; + file f( temp.name(), + BOOST_IOS::in | BOOST_IOS::out | + BOOST_IOS::trunc | BOOST_IOS::binary); + filtering_stream io(f); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within a file, in chunks" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("seekable file test"); + test->add(BOOST_TEST_CASE(&seekable_file_test)); + return test; +} diff --git a/libs/iostreams/test/seekable_filter_test.cpp b/libs/iostreams/test/seekable_filter_test.cpp new file mode 100644 index 0000000000..afd0af8fce --- /dev/null +++ b/libs/iostreams/test/seekable_filter_test.cpp @@ -0,0 +1,95 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../example/container_device.hpp" // We use container_device instead +#include "detail/filters.hpp" // of make_iterator_range to +#include "detail/temp_file.hpp" // reduce dependence on Boost.Range +#include "detail/verification.hpp" + + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::example; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + + +// Code generation bugs cause tests to fail with global optimization. +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("g", off) +#endif + +void seekable_filter_test() +{ + { + vector test(data_reps * data_length(), '0'); + filtering_stream io; + io.push(identity_seekable_filter()); + io.push(container_device< vector >(test)); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within a file, in chars" + ); + } + + { + vector test(data_reps * data_length(), '0'); + filtering_stream io; + io.push(identity_seekable_filter()); + io.push(container_device< vector >(test)); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within a file, in chunks" + ); + } + + { + vector test(data_reps * data_length(), '0'); + filtering_stream io; + io.push(identity_seekable_multichar_filter()); + io.push(container_device< vector >(test)); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chars(io), + "failed seeking within a file, in chars" + ); + } + + { + vector test(data_reps * data_length(), '0'); + filtering_stream io; + io.push(identity_seekable_multichar_filter()); + io.push(container_device< vector >(test)); + io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit); + BOOST_CHECK_MESSAGE( + test_seekable_in_chunks(io), + "failed seeking within a file, in chunks" + ); + } +} + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# pragma optimize("", on) +#endif + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("seekable filter test"); + test->add(BOOST_TEST_CASE(&seekable_filter_test)); + return test; +} diff --git a/libs/iostreams/test/sequence_test.cpp b/libs/iostreams/test/sequence_test.cpp new file mode 100644 index 0000000000..9dd182ccb8 --- /dev/null +++ b/libs/iostreams/test/sequence_test.cpp @@ -0,0 +1,24 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 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. + +#include +#include "read_input_seq_test.hpp" +#include "read_seekable_seq_test.hpp" +#include "write_output_seq_test.hpp" +#include "write_seekable_seq_test.hpp" + +using boost::unit_test::test_suite; + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("sequence test"); + test->add(BOOST_TEST_CASE(&read_input_sequence_test)); + test->add(BOOST_TEST_CASE(&read_seekable_sequence_test)); + test->add(BOOST_TEST_CASE(&write_output_sequence_test)); + test->add(BOOST_TEST_CASE(&write_seekable_sequence_test)); + return test; +} diff --git a/libs/iostreams/test/slice_test.cpp b/libs/iostreams/test/slice_test.cpp new file mode 100644 index 0000000000..2ec42d542e --- /dev/null +++ b/libs/iostreams/test/slice_test.cpp @@ -0,0 +1,17 @@ +/* + * 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. + + * File: test/slice_test.hpp + * Date: Sun Jan 06 12:57:30 MST 2008 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + * + * Tests the overloaded function template boost::iostreams::slice. + */ + +#define BOOST_RESTRICT_USE_SLICE +#include "restrict_test.cpp" diff --git a/libs/iostreams/test/stdio_filter_test.cpp b/libs/iostreams/test/stdio_filter_test.cpp new file mode 100644 index 0000000000..6bcbe31567 --- /dev/null +++ b/libs/iostreams/test/stdio_filter_test.cpp @@ -0,0 +1,144 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +// Must come last. +#include // BCC 5.x. + +using namespace boost::iostreams; +using boost::unit_test::test_suite; + +struct toupper_stdio_filter : stdio_filter { + void do_filter() + { + int c; + while ((c = std::cin.get()) != EOF) + std::cout.put(std::toupper((unsigned char)c)); + } +}; + +struct tolower_stdio_filter : stdio_filter { + void do_filter() + { + int c; + while ((c = std::cin.get()) != EOF) + std::cout.put(std::tolower((unsigned char)c)); + } +}; + +struct padding_stdio_filter : stdio_filter { + padding_stdio_filter(char pad_char) : pad_char_(pad_char) { } + void do_filter() + { + int c; + while ((c = std::cin.get()) != EOF) { + std::cout.put(c); + std::cout.put(pad_char_); + } + } + char pad_char_; +}; + +void read_stdio_filter() +{ + using namespace boost::iostreams::test; + + test_file src1, src2; + filtering_istream first, second; + + first.push(toupper_filter()); + first.push(padding_filter('a')); + first.push(file_source(src1.name(), in_mode)); + second.push(toupper_stdio_filter()); + second.push(padding_stdio_filter('a')); + second.push(file_source(src2.name(), in_mode)); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a stdio_filter" + ); + + first.reset(); + first.push(padding_filter('a')); + first.push(toupper_filter()); + first.push(file_source(src1.name(), in_mode)); + second.reset(); + second.push(padding_stdio_filter('a')); + second.push(toupper_stdio_filter()); + second.push(file_source(src2.name(), in_mode)); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a stdio_filter" + ); +} + +void write_stdio_filter() +{ + using namespace std; + using namespace boost::iostreams::test; + + temp_file dest1, dest2; + filtering_ostream out1, out2; + + out1.push(tolower_filter()); + out1.push(padding_filter('a')); + out1.push(file_sink(dest1.name(), in_mode)); + out2.push(tolower_stdio_filter()); + out2.push(padding_stdio_filter('a')); + out2.push(file_sink(dest2.name(), in_mode)); + write_data_in_chunks(out1); + write_data_in_chunks(out2); + out1.reset(); + out2.reset(); + + { + ifstream first(dest1.name().c_str()); + ifstream second(dest2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed writing to a stdio_filter" + ); + } + + out1.push(padding_filter('a')); + out1.push(tolower_filter()); + out1.push(file_sink(dest1.name(), in_mode)); + out2.push(padding_stdio_filter('a')); + out2.push(tolower_stdio_filter()); + out2.push(file_sink(dest2.name(), in_mode)); + write_data_in_chunks(out1); + write_data_in_chunks(out2); + out1.reset(); + out2.reset(); + + { + ifstream first(dest1.name().c_str()); + ifstream second(dest2.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed writing to a stdio_filter" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("line_filter test"); + test->add(BOOST_TEST_CASE(&read_stdio_filter)); + test->add(BOOST_TEST_CASE(&write_stdio_filter)); + return test; +} + +#include // BCC 5.x. diff --git a/libs/iostreams/test/stream_offset_32bit_test.cpp b/libs/iostreams/test/stream_offset_32bit_test.cpp new file mode 100644 index 0000000000..542e31cbb3 --- /dev/null +++ b/libs/iostreams/test/stream_offset_32bit_test.cpp @@ -0,0 +1,51 @@ +/* + * 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. + + * File: libs/iostreams/test/stream_offset_32bit_test.cpp + * Date: Sun Dec 23 21:11:23 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + * + * Tests the functions defined in the header "boost/iostreams/positioning.hpp" + * with small (32-bit) file offsets. + */ + +#include +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using boost::unit_test::test_suite; + +void stream_offset_32bit_test() +{ + stream_offset small_file = 1000000; + stream_offset off = -small_file; + streampos pos = offset_to_position(off); + + while (off < small_file) + { + BOOST_CHECK(off == position_to_offset(offset_to_position(off))); + BOOST_CHECK(pos == offset_to_position(position_to_offset(pos))); + off += 20000; + pos += 20000; + BOOST_CHECK(off == position_to_offset(offset_to_position(off))); + BOOST_CHECK(pos == offset_to_position(position_to_offset(pos))); + off -= 10000; + pos -= 10000; + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("stream_offset 32-bit test"); + test->add(BOOST_TEST_CASE(&stream_offset_32bit_test)); + return test; +} diff --git a/libs/iostreams/test/stream_offset_64bit_test.cpp b/libs/iostreams/test/stream_offset_64bit_test.cpp new file mode 100644 index 0000000000..6ebda4f18d --- /dev/null +++ b/libs/iostreams/test/stream_offset_64bit_test.cpp @@ -0,0 +1,85 @@ +/* + * 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. + + * File: libs/iostreams/test/stream_offset_64bit_test.cpp + * Date: Sun Dec 23 21:11:23 MST 2007 + * Copyright: 2007-2008 CodeRage, LLC + * Author: Jonathan Turkanis + * Contact: turkanis at coderage dot com + * + * Tests the functions defined in the header "boost/iostreams/positioning.hpp" + * with large (64-bit) file offsets. + */ + +#include // fpos_t +#include +#include +#include // BOOST_MSVC +#include +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using boost::unit_test::test_suite; + +#ifdef BOOST_MSVC +# pragma warning(disable:4127) +#endif + +void stream_offset_64bit_test() +{ + stream_offset large_file = (stream_offset) 100 * + (stream_offset) 1024 * + (stream_offset) 1024 * + (stream_offset) 1024; + stream_offset first = -large_file - (-large_file) % 10000000; + stream_offset last = large_file - large_file % 10000000; + + for (stream_offset off = first; off < last; off += 10000000) + { + if (off != position_to_offset(offset_to_position(off))) { + cout << "****************************************\n" + << "* sizeof(fpos_t) = " << sizeof(fpos_t) << "\n" + << "* sizeof(streamoff) = " << sizeof(streamoff) << "\n" + << "* sizeof(stream_offset) = " + << sizeof(stream_offset) << "\n" + << "****************************************\n"; + stringstream s; + s << "off != position_to_offset(offset_to_position(off)) " + "failed for (off >> 32) == 0x" + << hex + << static_cast(off >> 32) + << " and (off & 0xFFFFFFFF) == 0x" + << static_cast(off & 0xFFFFFFFF) + << std::endl; + BOOST_REQUIRE_MESSAGE(0, s.str().c_str()); + } + } +} + +void stream_offset_64bit_test2() +{ + boost::int64_t val = boost::int64_t(1) << 31; + std::streampos pos = boost::iostreams::offset_to_position(val); + pos -= 2; + BOOST_CHECK_EQUAL(val - 2, boost::iostreams::position_to_offset(pos)); + + val = -val; + pos = boost::iostreams::offset_to_position(val); + pos += 2; + BOOST_CHECK_EQUAL(val + 2, boost::iostreams::position_to_offset(pos)); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("stream_offset 64-bit test"); + test->add(BOOST_TEST_CASE(&stream_offset_64bit_test)); + test->add(BOOST_TEST_CASE(&stream_offset_64bit_test2)); + return test; +} diff --git a/libs/iostreams/test/stream_state_test.cpp b/libs/iostreams/test/stream_state_test.cpp new file mode 100644 index 0000000000..8d2a560c4a --- /dev/null +++ b/libs/iostreams/test/stream_state_test.cpp @@ -0,0 +1,161 @@ +// (C) Copyright Frank Birbacher 2007 +// 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. + +#include // tags. +#include // openmode, seekdir, int types. +#include +#include +#include +#include +#include + +using namespace boost::iostreams; +using boost::unit_test::test_suite; + +/* + * This test unit uses a custom device to trigger errors. The device supports + * input, output, and seek according to the SeekableDevice concept. And each + * of the required functions throw a special detail::bad_xxx exception. This + * should trigger the iostreams::stream to set the badbit status flag. + * Additionally the exception can be propagated to the caller if the exception + * mask of the stream allows exceptions. + * + * The stream offers four different functions: read, write, seekg, and seekp. + * Each of them is tested with three different error reporting concepts: + * test by reading status flags, test by propagated exception, and test by + * calling std::ios_base::exceptions when badbit is already set. + * + * In each case all of the status checking functions of a stream are checked. + */ + +//------------------Definition of error_device--------------------------------// + +// Device whose member functions throw +struct error_device { + typedef char char_type; + typedef seekable_device_tag category; + error_device(char const*) {} + std::streamsize read(char_type*, std::streamsize) + { + throw detail::bad_read(); + } + std::streamsize write(const char_type*, std::streamsize) + { + throw detail::bad_write(); + } + std::streampos seek(stream_offset, BOOST_IOS::seekdir) + { + throw detail::bad_seek(); + } +}; + +typedef stream test_stream; + +//------------------Stream state tester---------------------------------------// + +void check_stream_for_badbit(std::iostream& str) +{ + BOOST_CHECK_MESSAGE(!str.good(), "stream still good"); + BOOST_CHECK_MESSAGE(!str.eof(), "eofbit set but not expected"); + BOOST_CHECK_MESSAGE(str.bad(), "stream did not set badbit"); + BOOST_CHECK_MESSAGE(str.fail(), "stream did not fail"); + BOOST_CHECK_MESSAGE(str.operator ! (), + "stream does not report failure by operator !"); + BOOST_CHECK_MESSAGE(0 == str.operator void* (), + "stream does not report failure by operator void*"); +} + +//------------------Test case generators--------------------------------------// + +template +struct wrap_nothrow { + static void execute() + { + test_stream stream("foo"); + BOOST_CHECK_NO_THROW( function(stream) ); + check_stream_for_badbit(stream); + } +}; + +template +struct wrap_throw { + static void execute() + { + typedef std::ios_base ios; + test_stream stream("foo"); + + stream.exceptions(ios::failbit | ios::badbit); + BOOST_CHECK_THROW( function(stream), std::exception ); + + check_stream_for_badbit(stream); + } +}; + +template +struct wrap_throw_delayed { + static void execute() + { + typedef std::ios_base ios; + test_stream stream("foo"); + + function(stream); + BOOST_CHECK_THROW( + stream.exceptions(ios::failbit | ios::badbit), + ios::failure + ); + + check_stream_for_badbit(stream); + } +}; + +//------------------Stream operations that throw------------------------------// + +void test_read(std::iostream& str) +{ + char data[10]; + str.read(data, 10); +} + +void test_write(std::iostream& str) +{ + char data[10] = {0}; + str.write(data, 10); + //force use of streambuf + str.flush(); +} + +void test_seekg(std::iostream& str) +{ + str.seekg(10); +} + +void test_seekp(std::iostream& str) +{ + str.seekp(10); +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("stream state test"); + + test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_read>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw <&test_read>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_read>::execute)); + + test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_write>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw <&test_write>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_write>::execute)); + + test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekg>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekg>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekg>::execute)); + + test->add(BOOST_TEST_CASE(&wrap_nothrow <&test_seekp>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw <&test_seekp>::execute)); + test->add(BOOST_TEST_CASE(&wrap_throw_delayed<&test_seekp>::execute)); + + return test; +} diff --git a/libs/iostreams/test/symmetric_filter_test.cpp b/libs/iostreams/test/symmetric_filter_test.cpp new file mode 100644 index 0000000000..6f84f10c8b --- /dev/null +++ b/libs/iostreams/test/symmetric_filter_test.cpp @@ -0,0 +1,182 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "./detail/constants.hpp" +#include "detail/operation_sequence.hpp" +#include "./detail/temp_file.hpp" +#include "./detail/verification.hpp" + +// Must come last. +#include + +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; +namespace io = boost::iostreams; + +// Note: The filter is given an internal buffer -- unnecessary in this simple +// case -- to stress test symmetric_filter. +struct toupper_symmetric_filter_impl { + typedef char char_type; + explicit toupper_symmetric_filter_impl( + std::streamsize buffer_size = + default_filter_buffer_size + ) + : buf_(buffer_size) + { + buf_.set(0, 0); + } + bool filter( const char*& src_begin, const char* src_end, + char*& dest_begin, char* dest_end, bool /* flush */ ) + { + while ( can_read(src_begin, src_end) || + can_write(dest_begin, dest_end) ) + { + if (can_read(src_begin, src_end)) + read(src_begin, src_end); + if (can_write(dest_begin, dest_end)) + write(dest_begin, dest_end); + } + bool result = buf_.ptr() != buf_.eptr(); + return result; + } + void close() { buf_.set(0, 0); } + void read(const char*& src_begin, const char* src_end) + { + std::ptrdiff_t count = + (std::min) ( src_end - src_begin, + static_cast(buf_.size()) - + (buf_.eptr() - buf_.data()) ); + while (count-- > 0) + *buf_.eptr()++ = std::toupper(*src_begin++); + } + void write(char*& dest_begin, char* dest_end) + { + std::ptrdiff_t count = + (std::min) ( dest_end - dest_begin, + buf_.eptr() - buf_.ptr() ); + while (count-- > 0) + *dest_begin++ = *buf_.ptr()++; + if (buf_.ptr() == buf_.eptr()) + buf_.set(0, 0); + } + bool can_read(const char*& src_begin, const char* src_end) + { return src_begin != src_end && buf_.eptr() != buf_.end(); } + bool can_write(char*& dest_begin, char* dest_end) + { return dest_begin != dest_end && buf_.ptr() != buf_.eptr(); } + boost::iostreams::detail::buffer buf_; +}; + +typedef symmetric_filter + toupper_symmetric_filter; + +void read_symmetric_filter() +{ + test_file test; + uppercase_file upper; + BOOST_CHECK( + test_input_filter( toupper_symmetric_filter(default_filter_buffer_size), + file_source(test.name(), in_mode), + file_source(upper.name(), in_mode) ) + ); +} + +void write_symmetric_filter() +{ + test_file test; + uppercase_file upper; + BOOST_CHECK( + test_output_filter( toupper_symmetric_filter(default_filter_buffer_size), + file_source(test.name(), in_mode), + file_source(upper.name(), in_mode) ) + ); +} + +void close_symmetric_filter() +{ + // Test input + { + operation_sequence seq; + chain ch; + ch.push( + io::symmetric_filter + (1, seq.new_operation(2)) + ); + ch.push(closable_device(seq.new_operation(1))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Test output + { + operation_sequence seq; + chain ch; + ch.push( + io::symmetric_filter + (1, seq.new_operation(1)) + ); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +#ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS + +struct wcopy_filter_impl { + typedef wchar_t char_type; + bool filter( const wchar_t*& src_begin, const wchar_t* src_end, + wchar_t*& dest_begin, wchar_t* dest_end, bool /* flush */ ) + { + if(src_begin != src_end && dest_begin != dest_end) { + *dest_begin++ = *src_begin++; + } + return false; + } + void close() {} +}; + +typedef symmetric_filter wcopy_filter; + +void wide_symmetric_filter() +{ + { + warray_source src(wide_data(), wide_data() + data_length()); + std::wstring dest; + io::copy(src, io::compose(wcopy_filter(16), io::back_inserter(dest))); + BOOST_CHECK(dest == wide_data()); + } + { + warray_source src(wide_data(), wide_data() + data_length()); + std::wstring dest; + io::copy(io::compose(wcopy_filter(16), src), io::back_inserter(dest)); + BOOST_CHECK(dest == wide_data()); + } +} + +#endif + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("symmetric_filter test"); + test->add(BOOST_TEST_CASE(&read_symmetric_filter)); + test->add(BOOST_TEST_CASE(&write_symmetric_filter)); + test->add(BOOST_TEST_CASE(&close_symmetric_filter)); +#ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS + test->add(BOOST_TEST_CASE(&wide_symmetric_filter)); +#endif + return test; +} + +#include diff --git a/libs/iostreams/test/tee_test.cpp b/libs/iostreams/test/tee_test.cpp new file mode 100644 index 0000000000..fbc724fce3 --- /dev/null +++ b/libs/iostreams/test/tee_test.cpp @@ -0,0 +1,370 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include +#include "detail/closable.hpp" +#include "detail/operation_sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +void read_write_test() +{ + { + test_file src1, src2; + temp_file dest; + filtering_istream first, second; + first.push(tee(file_sink(dest.name(), out_mode))); + first.push(file_source(src1.name(), in_mode)); + second.push(file_source(src2.name(), in_mode)); + compare_streams_in_chars(first, second); // ignore return value + first.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), src1.name()), + "failed reading from a tee_filter in chars" + ); + } + + { + test_file src1, src2; + temp_file dest; + filtering_istream first, second; + first.push(tee(file_sink(dest.name(), out_mode))); + first.push(file_source(src1.name(), in_mode)); + second.push(file_source(src2.name(), in_mode)); + compare_streams_in_chunks(first, second); // ignore return value + first.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), src1.name()), + "failed reading from a tee_filter in chunks" + ); + } + + { + temp_file dest1; + temp_file dest2; + filtering_ostream out; + out.push(tee(file_sink(dest1.name(), out_mode))); + out.push(file_sink(dest2.name(), out_mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), dest2.name()), + "failed writing to a tee_filter in chars" + ); + } + + { + temp_file dest1; + temp_file dest2; + filtering_ostream out; + out.push(tee(file_sink(dest1.name(), out_mode))); + out.push(file_sink(dest2.name(), out_mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), dest2.name()), + "failed writing to a tee_filter in chunks" + ); + } + + { + test_file src1, src2; + temp_file dest; + filtering_istream first, second; + first.push( tee( file_source(src1.name(), in_mode), + file_sink(dest.name(), out_mode) ) ); + second.push(file_source(src2.name(), in_mode)); + compare_streams_in_chars(first, second); // ignore return value + first.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), src1.name()), + "failed reading from a tee_device in chars" + ); + } + + { + test_file src1, src2; + temp_file dest; + filtering_istream first, second; + first.push( tee( file_source(src1.name(), in_mode), + file_sink(dest.name(), out_mode) ) ); + second.push(file_source(src2.name(), in_mode)); + compare_streams_in_chunks(first, second); // ignore return value + first.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), src1.name()), + "failed reading from a tee_device in chunks" + ); + } + + { + temp_file dest1; + temp_file dest2; + filtering_ostream out; + out.push( tee( file_sink(dest1.name(), out_mode), + file_sink(dest2.name(), out_mode) ) ); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), dest2.name()), + "failed writing to a tee_device in chars" + ); + } + + { + temp_file dest1; + temp_file dest2; + filtering_ostream out; + out.push( tee( file_sink(dest1.name(), out_mode), + file_sink(dest2.name(), out_mode) ) ); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest1.name(), dest2.name()), + "failed writing to a tee_device in chunks" + ); + } +} + +void close_test() +{ + // Note: The implementation of tee_device closes the first + // sink before the second + + // Tee two sinks (Borland <= 5.8.2 needs a little help compiling this case, + // but it executes the closing algorithm correctly) + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + closable_device(seq.new_operation(1)), + closable_device< + #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + borland_output + #else + output + #endif + >(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee two bidirectional devices + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + closable_device( + seq.new_operation(1), + seq.new_operation(2) + ), + closable_device( + seq.new_operation(3), + seq.new_operation(4) + ) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee two seekable devices + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + closable_device(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a sink + { + operation_sequence seq; + chain ch; + ch.push(boost::iostreams::tee(closable_device(seq.new_operation(1)))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a bidirectional device + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + closable_device( + seq.new_operation(1), + seq.new_operation(2) + ) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a seekable device + { + operation_sequence seq; + chain ch; + ch.push(boost::iostreams::tee(closable_device(seq.new_operation(1)))); + ch.push(closable_device(seq.new_operation(2))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } +} + +void tee_composite_test() +{ + // This test is probably redundant, given the above test and the tests in + // compose_test.cpp, but it verifies that ticket #1002 is fixed + + // Tee a composite sink with a sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ), + closable_device(seq.new_operation(3)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a composite bidirectional device with a sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ), + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ), + closable_device(seq.new_operation(5)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a composite composite seekable device with a sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ), + closable_device(seq.new_operation(3)) + ) + ); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + + // Tee a composite sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a composite bidirectional device with a sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter( + seq.new_operation(2), + seq.new_operation(3) + ), + closable_device( + seq.new_operation(1), + seq.new_operation(4) + ) + ) + ) + ); + ch.push(closable_device(seq.new_operation(5))); + BOOST_CHECK_NO_THROW(ch.reset()); + BOOST_CHECK_OPERATION_SEQUENCE(seq); + } + + // Tee a composite composite seekable device with a sink + { + operation_sequence seq; + chain ch; + ch.push( + boost::iostreams::tee( + boost::iostreams::compose( + closable_filter(seq.new_operation(1)), + closable_device(seq.new_operation(2)) + ) + ) + ); + ch.push(closable_device(seq.new_operation(3))); + 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("tee test"); + test->add(BOOST_TEST_CASE(&read_write_test)); + test->add(BOOST_TEST_CASE(&close_test)); + return test; +} diff --git a/libs/iostreams/test/wide_stream_test.cpp b/libs/iostreams/test/wide_stream_test.cpp new file mode 100644 index 0000000000..425485ad1a --- /dev/null +++ b/libs/iostreams/test/wide_stream_test.cpp @@ -0,0 +1,145 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#ifdef BOOST_IOSTREAMS_NO_WIDE_STREAMS +# error wide streams not supported on this platform +#endif + +#include +#include +#include +#include +#include +#include +#include "../example/container_device.hpp" // We use container_device instead +#include "detail/filters.hpp" // of make_iterator_range to +#include "detail/sequence.hpp" // reduce dependence on Boost.Range +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +using boost::unit_test::test_suite; + +void read_wide_input_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::example; + using namespace boost::iostreams::test; + + test_sequence seq; + container_device< test_sequence > source(seq); + + { + filtering_wistream first(source, 0); + basic_istringstream second( + basic_string(seq.begin(), seq.end()) + ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a filter_wistream in chars with no buffer" + ); + } + + { + filtering_wistream first(source, 0); + basic_istringstream second( + basic_string(seq.begin(), seq.end()) + ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filter_wistream in chunks with no buffer" + ); + } + + { + filtering_wistream first(source); + basic_istringstream second( + basic_string(seq.begin(), seq.end()) + ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chars(first, second), + "failed reading from a filter_wistream in chars with large buffer" + ); + } + + { + filtering_wistream first(source); + basic_istringstream second( + basic_string(seq.begin(), seq.end()) + ); + BOOST_CHECK_MESSAGE( + compare_streams_in_chunks(first, second), + "failed reading from a filter_wistream in chunks with large buffer" + ); + } +} + +void write_wide_output_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + { + vector first; + test_sequence second; + filtering_wostream out(iostreams::back_inserter(first), 0); + write_data_in_chars(out); + BOOST_CHECK_MESSAGE( + first.size() == second.size() && + std::equal(first.begin(), first.end(), second.begin()), + "failed writing to filtering_wostream in chars with no buffer" + ); + } + + { + vector first; + test_sequence second; + filtering_wostream out(iostreams::back_inserter(first), 0); + write_data_in_chunks(out); + BOOST_CHECK_MESSAGE( + first.size() == second.size() && + std::equal(first.begin(), first.end(), second.begin()), + "failed writing to filtering_wostream in chunks with no buffer" + ); + } + + { + vector first; + test_sequence second; + filtering_wostream out(iostreams::back_inserter(first), 0); + write_data_in_chars(out); + BOOST_CHECK_MESSAGE( + first.size() == second.size() && + std::equal(first.begin(), first.end(), second.begin()), + "failed writing to filtering_wostream in chars with large buffer" + ); + } + + { + vector first; + test_sequence second; + filtering_wostream out(iostreams::back_inserter(first)); + write_data_in_chunks(out); + BOOST_CHECK_MESSAGE( + first.size() == second.size() && + std::equal(first.begin(), first.end(), second.begin()), + "failed writing to filtering_wostream in chunks with large buffer" + ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("wide stream test"); + test->add(BOOST_TEST_CASE(&read_wide_input_test)); + test->add(BOOST_TEST_CASE(&write_wide_output_test)); + return test; +} diff --git a/libs/iostreams/test/write_bidir_filter_test.hpp b/libs/iostreams/test/write_bidir_filter_test.hpp new file mode 100644 index 0000000000..8865ec1805 --- /dev/null +++ b/libs/iostreams/test/write_bidir_filter_test.hpp @@ -0,0 +1,134 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_INOUT_FILTER_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_INOUT_FILTER_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_bidirectional_filter_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + lowercase_file lower; + BOOST_IOS::openmode mode = out_mode | BOOST_IOS::trunc; + + { + temp_file lower2; + filebuf dest; + filtering_stream out; + dest.open(lower2.name().c_str(), mode); + out.push(combine(toupper_filter(), tolower_filter())); + out.push(dest); + write_data_in_chars(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chars with an " + "output filter" + ); + } + + { + // OutputFilter. + temp_file lower2; + filebuf dest; + filtering_stream out; + out.push(combine(toupper_filter(), tolower_filter())); + dest.open(lower2.name().c_str(), mode); + out.push(dest); + write_data_in_chunks(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chunks with an " + "output filter" + ); + } + + { + temp_file lower2; + filebuf dest; + filtering_stream out; + out.push(combine(toupper_filter(), tolower_multichar_filter()), 0); + dest.open(lower2.name().c_str(), mode); + out.push(dest); + write_data_in_chars(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chars " + "with a multichar output filter with no buffer" + ); + } + + { + temp_file lower2; + filebuf dest; + filtering_stream out; + out.push(combine(toupper_filter(), tolower_multichar_filter()), 0); + dest.open(lower2.name().c_str(), mode); + out.push(dest); + write_data_in_chunks(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chunks " + "with a multichar output filter with no buffer" + ); + } + + { + temp_file lower2; + filebuf dest; + filtering_stream out; + out.push(combine(toupper_filter(), tolower_multichar_filter())); + dest.open(lower2.name().c_str(), mode); + out.push(dest); + write_data_in_chars(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chars " + "with a multichar output filter" + ); + } + + { + temp_file lower2; + filebuf dest; + filtering_stream out; + out.push(combine(toupper_filter(), tolower_multichar_filter())); + dest.open(lower2.name().c_str(), mode); + out.push(dest); + write_data_in_chunks(out); + out.reset(); + dest.close(); + BOOST_CHECK_MESSAGE( + compare_files(lower2.name(), lower.name()), + "failed writing to a filtering_stream in chunks " + "with a buffered output filter" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_FILTER_HPP_INCLUDED diff --git a/libs/iostreams/test/write_bidir_streambuf_test.hpp b/libs/iostreams/test/write_bidir_streambuf_test.hpp new file mode 100644 index 0000000000..7dadaca08f --- /dev/null +++ b/libs/iostreams/test/write_bidir_streambuf_test.hpp @@ -0,0 +1,87 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED + +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_bidirectional_streambuf_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + temp_file test2; + { + filebuf dest; + dest.open(test2.name().c_str(), out_mode); + filtering_stream out(dest, 0); + write_data_in_chars(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream based " + "on a streambuf in chars with no buffer" + ); + } + + { + temp_file test2; + { + filebuf dest; + dest.open(test2.name().c_str(), out_mode); + filtering_stream out(dest, 0); + write_data_in_chunks(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream based " + "on a streambuf in chunks with no buffer" + ); + } + + { + temp_file test2; + { + filebuf dest; + dest.open(test2.name().c_str(), out_mode); + filtering_stream out(dest); + write_data_in_chars(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream based " + "on a streambuf in chars with large buffer" + ); + } + + { + temp_file test2; + { + filebuf dest; + dest.open(test2.name().c_str(), out_mode); + filtering_stream out(dest); + write_data_in_chunks(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream based " + "on a streambuf in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_STREAMBUF_HPP_INCLUDED diff --git a/libs/iostreams/test/write_bidir_test.hpp b/libs/iostreams/test/write_bidir_test.hpp new file mode 100644 index 0000000000..12cc3ef5d9 --- /dev/null +++ b/libs/iostreams/test/write_bidir_test.hpp @@ -0,0 +1,89 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_bidirectional_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + temp_file dest; + temp_file src; // Dummy; + filtering_stream out( + combine(file_source(src.name()), file_sink(dest.name(), out_mode)), 0 + ); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), test.name()), + "failed writing to filtering_stream in chars " + "with no buffer" + ); + } + + { + temp_file dest; + temp_file src; // Dummy; + filtering_stream out( + combine(file_source(src.name()), file_sink(dest.name(), out_mode)), 0 + ); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), test.name()), + "failed writing to filtering_stream in chunks " + "with no buffer" + ); + } + + { + temp_file dest; + temp_file src; // Dummy; + filtering_stream out( + combine(file_source(src.name()), file_sink(dest.name(), out_mode)) + ); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), test.name()), + "failed writing to filtering_stream in chars " + "with large buffer" + ); + } + + { + temp_file dest; + temp_file src; // Dummy; + filtering_stream out( + combine(file_source(src.name()), file_sink(dest.name(), out_mode)) + ); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), test.name()), + "failed writing to filtering_stream in chunks " + "with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_BIDIRECTIONAL_HPP_INCLUDED diff --git a/libs/iostreams/test/write_output_filter_test.hpp b/libs/iostreams/test/write_output_filter_test.hpp new file mode 100644 index 0000000000..34a367319c --- /dev/null +++ b/libs/iostreams/test/write_output_filter_test.hpp @@ -0,0 +1,114 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_FILTER_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_FILTER_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/filters.hpp" +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_output_filter_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + lowercase_file lower; + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_filter()); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chars with an " + "output filter" + ); + } + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_filter()); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chunks with an " + "output filter" + ); + } + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_multichar_filter(), 0); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chars with a " + "multichar output filter with no buffer" + ); + } + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_multichar_filter(), 0); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chunks with a " + "multichar output filter with no buffer" + ); + } + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_multichar_filter()); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chars with a " + "multichar output filter" + ); + } + + { + temp_file dest; + filtering_ostream out; + out.push(tolower_multichar_filter()); + out.push(file_sink(dest.name(), out_mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(dest.name(), lower.name()), + "failed writing to a filtering_ostream in chunks with a " + "multichar output filter" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_FILTER_HPP_INCLUDED diff --git a/libs/iostreams/test/write_output_iterator_test.hpp b/libs/iostreams/test/write_output_iterator_test.hpp new file mode 100644 index 0000000000..6cedc16185 --- /dev/null +++ b/libs/iostreams/test/write_output_iterator_test.hpp @@ -0,0 +1,85 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_ITERATOR_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_ITERATOR_HPP_INCLUDED + +#include +#include // Back inserter. +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +// Note: adding raw inserter iterators to chains is not supported +// on VC6. + +void write_output_iterator_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + vector first; + filtering_ostream out; + out.push(std::back_inserter(first), 0); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on an " + "output iterator in chars with no buffer" + ); + } + + { + vector first; + filtering_ostream out; + out.push(std::back_inserter(first), 0); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on an " + "output iterator in chunks with no buffer" + ); + } + + { + vector first; + filtering_ostream out; + out.push(std::back_inserter(first)); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on an " + "output iterator in chars with large buffer" + ); + } + + { + vector first; + filtering_ostream out; + out.push(std::back_inserter(first)); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on an " + "output iterator in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_ITERATOR_HPP_INCLUDED diff --git a/libs/iostreams/test/write_output_ostream_test.hpp b/libs/iostreams/test/write_output_ostream_test.hpp new file mode 100644 index 0000000000..c6dd713f1a --- /dev/null +++ b/libs/iostreams/test/write_output_ostream_test.hpp @@ -0,0 +1,84 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_OSTREAM_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_OSTREAM_HPP_INCLUDED + +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_output_ostream_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + temp_file test2; + { + ofstream dest(test2.name().c_str(), out_mode); + filtering_ostream out(dest, 0); + write_data_in_chars(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream based on an ostream " + "in chars with no buffer" + ); + } + + { + temp_file test2; + { + ofstream dest(test2.name().c_str(), out_mode); + filtering_ostream out(dest, 0); + write_data_in_chunks(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream based on an ostream " + "in chunks with no buffer" + ); + } + + { + test_file test2; + { + ofstream dest(test2.name().c_str(), out_mode); + filtering_ostream out(dest); + write_data_in_chars(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream based on an ostream " + "in chars with large buffer" + ); + } + + { + temp_file test2; + { + ofstream dest(test2.name().c_str(), out_mode); + filtering_ostream out(dest); + write_data_in_chunks(out); + } + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream based on an ostream " + "in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_OSTREAM_HPP_INCLUDED diff --git a/libs/iostreams/test/write_output_seq_test.hpp b/libs/iostreams/test/write_output_seq_test.hpp new file mode 100644 index 0000000000..2ff5fb4492 --- /dev/null +++ b/libs/iostreams/test/write_output_seq_test.hpp @@ -0,0 +1,78 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_SEQUENCE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_output_sequence_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + vector first(data_reps * data_length(), '?'); + filtering_ostream out(make_iterator_range(first), 0); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on a sequence " + "in chars with no buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_ostream out(make_iterator_range(first), 0); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on a sequence " + "in chunks with no buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_ostream out(make_iterator_range(first)); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on a sequence " + "in chars with large buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_ostream out(make_iterator_range(first)); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_ostream based on a sequence " + "in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/write_output_test.hpp b/libs/iostreams/test/write_output_test.hpp new file mode 100644 index 0000000000..d8e56abff8 --- /dev/null +++ b/libs/iostreams/test/write_output_test.hpp @@ -0,0 +1,73 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_output_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + temp_file test2; + filtering_ostream out(file_sink(test2.name(), out_mode), 0); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream in chars with no buffer" + ); + } + + { + temp_file test2; + filtering_ostream out(file_sink(test2.name(), out_mode), 0); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream in chunks with no buffer" + ); + } + + { + temp_file test2; + filtering_ostream out(file_sink(test2.name(), out_mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream in chars with buffer" + ); + } + + { + temp_file test2; + filtering_ostream out(file_sink(test2.name(), out_mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_ostream in chunks with buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_OUTPUT_HPP_INCLUDED diff --git a/libs/iostreams/test/write_seekable_seq_test.hpp b/libs/iostreams/test/write_seekable_seq_test.hpp new file mode 100644 index 0000000000..5fce08fb8c --- /dev/null +++ b/libs/iostreams/test/write_seekable_seq_test.hpp @@ -0,0 +1,79 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_SEQUENCE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_SEQUENCE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_seekable_sequence_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + + { + vector first(data_reps * data_length(), '?'); + filtering_stream out(make_iterator_range(first), 0); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_stream based on a " + "sequence in chars with no buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_stream out(make_iterator_range(first), 0); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_stream based on a " + "sequence in chunks with no buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_stream out(make_iterator_range(first)); + write_data_in_chars(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_stream based on a " + "sequence in chars with large buffer" + ); + } + + { + vector first(data_reps * data_length(), '?'); + filtering_stream out(make_iterator_range(first)); + write_data_in_chunks(out); + ifstream second(test.name().c_str()); + BOOST_CHECK_MESSAGE( + compare_container_and_stream(first, second), + "failed writing to filtering_stream based on a " + "sequence in chunks with large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_SEQUENCE_HPP_INCLUDED diff --git a/libs/iostreams/test/write_seekable_test.hpp b/libs/iostreams/test/write_seekable_test.hpp new file mode 100644 index 0000000000..cf83d0e86e --- /dev/null +++ b/libs/iostreams/test/write_seekable_test.hpp @@ -0,0 +1,77 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#ifndef BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_HPP_INCLUDED +#define BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_HPP_INCLUDED + +#include +#include +#include +#include +#include "detail/temp_file.hpp" +#include "detail/verification.hpp" + +void write_seekable_test() +{ + using namespace std; + using namespace boost; + using namespace boost::iostreams; + using namespace boost::iostreams::test; + + test_file test; + BOOST_IOS::openmode mode = out_mode | BOOST_IOS::trunc; + + { + temp_file test2; + filtering_stream out(file(test2.name(), mode), 0); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream in chars with" + "no buffer" + ); + } + + { + temp_file test2; + filtering_stream out(file(test2.name(), mode), 0); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream in chunks with" + "no buffer" + ); + } + + { + temp_file test2; + filtering_stream out(file(test2.name(), mode)); + write_data_in_chars(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream in chars with" + "large buffer" + ); + } + + { + temp_file test2; + filtering_stream out(file(test2.name(), mode)); + write_data_in_chunks(out); + out.reset(); + BOOST_CHECK_MESSAGE( + compare_files(test2.name(), test.name()), + "failed writing to filtering_stream in chunks with" + "large buffer" + ); + } +} + +#endif // #ifndef BOOST_IOSTREAMS_TEST_WRITE_SEEKABLE_HPP_INCLUDED diff --git a/libs/iostreams/test/zlib_test.cpp b/libs/iostreams/test/zlib_test.cpp new file mode 100644 index 0000000000..17ab340993 --- /dev/null +++ b/libs/iostreams/test/zlib_test.cpp @@ -0,0 +1,60 @@ +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2004-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. + +#include +#include +#include +#include +#include +#include +#include "detail/sequence.hpp" +#include "detail/verification.hpp" + +using namespace std; +using namespace boost; +using namespace boost::iostreams; +using namespace boost::iostreams::test; +using boost::unit_test::test_suite; + +struct zlib_alloc : std::allocator { }; + +void zlib_test() +{ + text_sequence data; + BOOST_CHECK( + test_filter_pair( zlib_compressor(), + zlib_decompressor(), + std::string(data.begin(), data.end()) ) + ); + BOOST_CHECK( + test_filter_pair( basic_zlib_compressor(), + basic_zlib_decompressor(), + std::string(data.begin(), data.end()) ) + ); + BOOST_CHECK( + test_filter_pair( zlib_compressor(), + zlib_decompressor(), + std::string() ) + ); + { + filtering_istream strm; + strm.push( zlib_compressor() ); + strm.push( null_source() ); + } + { + filtering_istream strm; + strm.push( zlib_decompressor() ); + strm.push( null_source() ); + } +} + +test_suite* init_unit_test_suite(int, char* []) +{ + test_suite* test = BOOST_TEST_SUITE("zlib test"); + test->add(BOOST_TEST_CASE(&zlib_test)); + return test; +} -- cgit v1.2.3