1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2004-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5 
6 // See http://www.boost.org/libs/iostreams for documentation.
7 
8 #include <boost/iostreams/detail/buffer.hpp>
9 #include <boost/iostreams/device/file.hpp>
10 #include <boost/iostreams/filter/symmetric.hpp>
11 #include <boost/iostreams/filter/test.hpp>
12 #include <boost/test/test_tools.hpp>
13 #include <boost/test/unit_test.hpp>
14 #include "detail/closable.hpp"
15 #include "./detail/constants.hpp"
16 #include "detail/operation_sequence.hpp"
17 #include "./detail/temp_file.hpp"
18 #include "./detail/verification.hpp"
19 
20 // Must come last.
21 #include <boost/iostreams/detail/config/disable_warnings.hpp>
22 
23 using namespace boost::iostreams;
24 using namespace boost::iostreams::test;
25 using boost::unit_test::test_suite;
26 namespace io = boost::iostreams;
27 
28 // Note: The filter is given an internal buffer -- unnecessary in this simple
29 // case -- to stress test symmetric_filter.
30 struct toupper_symmetric_filter_impl {
31     typedef char char_type;
toupper_symmetric_filter_impltoupper_symmetric_filter_impl32     explicit toupper_symmetric_filter_impl(
33                 std::streamsize buffer_size =
34                     default_filter_buffer_size
35              )
36         : buf_(buffer_size)
37     {
38         buf_.set(0, 0);
39     }
filtertoupper_symmetric_filter_impl40     bool filter( const char*& src_begin, const char* src_end,
41                  char*& dest_begin, char* dest_end, bool /* flush */ )
42     {
43         while ( can_read(src_begin, src_end) ||
44                 can_write(dest_begin, dest_end) )
45         {
46             if (can_read(src_begin, src_end))
47                 read(src_begin, src_end);
48             if (can_write(dest_begin, dest_end))
49                 write(dest_begin, dest_end);
50         }
51         bool result = buf_.ptr() != buf_.eptr();
52         return result;
53     }
closetoupper_symmetric_filter_impl54     void close() { buf_.set(0, 0); }
readtoupper_symmetric_filter_impl55     void read(const char*& src_begin, const char* src_end)
56     {
57         std::ptrdiff_t count =
58             (std::min) ( src_end - src_begin,
59                          static_cast<std::ptrdiff_t>(buf_.size()) -
60                              (buf_.eptr() - buf_.data()) );
61         while (count-- > 0)
62             *buf_.eptr()++ = std::toupper(*src_begin++);
63     }
writetoupper_symmetric_filter_impl64     void write(char*& dest_begin, char* dest_end)
65     {
66         std::ptrdiff_t count =
67             (std::min) ( dest_end - dest_begin,
68                          buf_.eptr() - buf_.ptr() );
69         while (count-- > 0)
70             *dest_begin++ = *buf_.ptr()++;
71         if (buf_.ptr() == buf_.eptr())
72             buf_.set(0, 0);
73     }
can_readtoupper_symmetric_filter_impl74     bool can_read(const char*& src_begin, const char* src_end)
75     { return src_begin != src_end && buf_.eptr() != buf_.end(); }
can_writetoupper_symmetric_filter_impl76     bool can_write(char*& dest_begin, char* dest_end)
77     { return dest_begin != dest_end && buf_.ptr() != buf_.eptr(); }
78     boost::iostreams::detail::buffer<char> buf_;
79 };
80 
81 typedef symmetric_filter<toupper_symmetric_filter_impl>
82         toupper_symmetric_filter;
83 
read_symmetric_filter()84 void read_symmetric_filter()
85 {
86     test_file       test;
87     uppercase_file  upper;
88     BOOST_CHECK(
89         test_input_filter( toupper_symmetric_filter(default_filter_buffer_size),
90                            file_source(test.name(), in_mode),
91                            file_source(upper.name(), in_mode) )
92     );
93 }
94 
write_symmetric_filter()95 void write_symmetric_filter()
96 {
97     test_file       test;
98     uppercase_file  upper;
99     BOOST_CHECK(
100         test_output_filter( toupper_symmetric_filter(default_filter_buffer_size),
101                             file_source(test.name(), in_mode),
102                             file_source(upper.name(), in_mode) )
103     );
104 }
105 
close_symmetric_filter()106 void close_symmetric_filter()
107 {
108     // Test input
109     {
110         operation_sequence  seq;
111         chain<input>        ch;
112         ch.push(
113             io::symmetric_filter<closable_symmetric_filter>
114                 (1, seq.new_operation(2))
115         );
116         ch.push(closable_device<input>(seq.new_operation(1)));
117         BOOST_CHECK_NO_THROW(ch.reset());
118         BOOST_CHECK_OPERATION_SEQUENCE(seq);
119     }
120 
121     // Test output
122     {
123         operation_sequence  seq;
124         chain<output>       ch;
125         ch.push(
126             io::symmetric_filter<closable_symmetric_filter>
127                 (1, seq.new_operation(1))
128         );
129         ch.push(closable_device<output>(seq.new_operation(2)));
130         BOOST_CHECK_NO_THROW(ch.reset());
131         BOOST_CHECK_OPERATION_SEQUENCE(seq);
132     }
133 }
134 
135 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
136 
137 struct wcopy_filter_impl {
138     typedef wchar_t char_type;
filterwcopy_filter_impl139     bool filter( const wchar_t*& src_begin, const wchar_t* src_end,
140                  wchar_t*& dest_begin, wchar_t* dest_end, bool /* flush */ )
141     {
142         if(src_begin != src_end && dest_begin != dest_end) {
143             *dest_begin++ = *src_begin++;
144         }
145         return false;
146     }
closewcopy_filter_impl147     void close() {}
148 };
149 
150 typedef symmetric_filter<wcopy_filter_impl> wcopy_filter;
151 
wide_symmetric_filter()152 void wide_symmetric_filter()
153 {
154     {
155         warray_source  src(wide_data(), wide_data() + data_length());
156         std::wstring   dest;
157         io::copy(src, io::compose(wcopy_filter(16), io::back_inserter(dest)));
158         BOOST_CHECK(dest == wide_data());
159     }
160     {
161         warray_source  src(wide_data(), wide_data() + data_length());
162         std::wstring   dest;
163         io::copy(io::compose(wcopy_filter(16), src), io::back_inserter(dest));
164         BOOST_CHECK(dest == wide_data());
165     }
166 }
167 
168 #endif
169 
init_unit_test_suite(int,char * [])170 test_suite* init_unit_test_suite(int, char* [])
171 {
172     test_suite* test = BOOST_TEST_SUITE("symmetric_filter test");
173     test->add(BOOST_TEST_CASE(&read_symmetric_filter));
174     test->add(BOOST_TEST_CASE(&write_symmetric_filter));
175     test->add(BOOST_TEST_CASE(&close_symmetric_filter));
176 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
177     test->add(BOOST_TEST_CASE(&wide_symmetric_filter));
178 #endif
179     return test;
180 }
181 
182 #include <boost/iostreams/detail/config/enable_warnings.hpp>
183