// (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; }