• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2005-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5 
6 // See http://www.boost.org/libs/iostreams for documentation.
7 
8 #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED
9 
10 #if defined(_MSC_VER)
11 # pragma once
12 #endif
13 
14 #include <boost/config.hpp>               // BOOST_MSVC,put size_t in std.
15 #include <boost/detail/workaround.hpp>
16 #include <algorithm>                      // min.
17 #include <cstddef>                        // size_t.
18 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) || \
19     BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
20     /**/
21 # include <cstdlib>                       // rand.
22 #endif
23 #include <cstring>                        // memcpy, strlen.
24 #include <iterator>
25 #include <string>
26 #include <vector>
27 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \
28     !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
29     /**/
30 # include <boost/random/linear_congruential.hpp>
31 # include <boost/random/uniform_smallint.hpp>
32 #endif
33 #include <boost/iostreams/categories.hpp>
34 #include <boost/iostreams/compose.hpp>
35 #include <boost/iostreams/copy.hpp>
36 #include <boost/iostreams/detail/bool_trait_def.hpp>
37 #include <boost/iostreams/detail/ios.hpp>
38 #include <boost/iostreams/device/array.hpp>
39 #include <boost/iostreams/device/back_inserter.hpp>
40 #include <boost/iostreams/operations.hpp>
41 #include <boost/mpl/bool.hpp>
42 #include <boost/type_traits/is_array.hpp>
43 #include <boost/type_traits/is_same.hpp>
44 
45 #undef memcpy
46 #undef rand
47 #undef strlen
48 
49 #if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__LIBCOMO__)
50 namespace std {
51     using ::memcpy;
52     using ::strlen;
53     #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) || \
54         BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
55         /**/
56         using ::rand;
57     #endif
58 }
59 #endif
60 
61 namespace boost { namespace iostreams {
62 
63 BOOST_IOSTREAMS_BOOL_TRAIT_DEF(is_string, std::basic_string, 3)
64 
65 const std::streamsize default_increment = 5;
66 
67 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \
68     !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
69     /**/
rand(std::streamsize inc)70     std::streamsize rand(std::streamsize inc)
71     {
72         static rand48                random_gen;
73         static uniform_smallint<int> random_dist(0, static_cast<int>(inc));
74         return random_dist(random_gen);
75     }
76 #else
rand(std::streamsize inc)77     std::streamsize rand(std::streamsize inc)
78     {
79         return (std::rand() * inc + 1) / RAND_MAX;
80     }
81 #endif
82 
83 class non_blocking_source {
84 public:
85     typedef char char_type;
86     struct category
87         : source_tag,
88           peekable_tag
89         { };
non_blocking_source(const std::string & data,std::streamsize inc=default_increment)90     explicit non_blocking_source( const std::string& data,
91                                   std::streamsize inc = default_increment )
92         : data_(data), inc_(inc), pos_(0)
93         { }
read(char * s,std::streamsize n)94     std::streamsize read(char* s, std::streamsize n)
95     {
96         using namespace std;
97         if (pos_ == static_cast<streamsize>(data_.size()))
98             return -1;
99         streamsize avail =
100             (std::min) (n, static_cast<streamsize>(data_.size() - pos_));
101         streamsize amt = (std::min) (rand(inc_), avail);
102         if (amt)
103             memcpy(s, data_.c_str() + pos_, static_cast<size_t>(amt));
104         pos_ += amt;
105         return amt;
106     }
107 
putback(char c)108     bool putback(char c)
109     {
110         if (pos_ > 0) {
111             data_[static_cast<std::string::size_type>(--pos_)] = c;
112             return true;
113         }
114         return false;
115     }
116 private:
117     std::string      data_;
118     std::streamsize  inc_, pos_;
119 };
120 
121 class non_blocking_sink : public sink {
122 public:
non_blocking_sink(std::string & dest,std::streamsize inc=default_increment)123     non_blocking_sink( std::string& dest,
124                        std::streamsize inc = default_increment )
125         : dest_(dest), inc_(inc)
126         { }
write(const char * s,std::streamsize n)127     std::streamsize write(const char* s, std::streamsize n)
128     {
129         std::streamsize amt = (std::min) (rand(inc_), n);
130         dest_.insert(dest_.end(), s, s + amt);
131         return amt;
132     }
133 private:
134     non_blocking_sink& operator=(const non_blocking_sink&);
135     std::string&     dest_;
136     std::streamsize  inc_;
137 };
138 
139 //--------------Definition of test_input_filter-------------------------------//
140 
141 template<typename Filter>
test_input_filter(Filter filter,const std::string & input,const std::string & output,mpl::true_)142 bool test_input_filter( Filter filter,
143                         const std::string& input,
144                         const std::string& output,
145                         mpl::true_ )
146 {
147     for ( int inc = default_increment;
148           inc < default_increment * 40;
149           inc += default_increment )
150     {
151         non_blocking_source  src(input, inc);
152         std::string          dest;
153         iostreams::copy(compose(filter, src), iostreams::back_inserter(dest));
154         if (dest != output)
155             return false;
156     }
157     return true;
158 }
159 
160 template<typename Filter, typename Source1, typename Source2>
test_input_filter(Filter filter,const Source1 & input,const Source2 & output,mpl::false_)161 bool test_input_filter( Filter filter,
162                         const Source1& input,
163                         const Source2& output,
164                         mpl::false_ )
165 {
166     std::string in;
167     std::string out;
168     iostreams::copy(input, iostreams::back_inserter(in));
169     iostreams::copy(output, iostreams::back_inserter(out));
170     return test_input_filter(filter, in, out);
171 }
172 
173 template<typename Filter, typename Source1, typename Source2>
test_input_filter(Filter filter,const Source1 & input,const Source2 & output)174 bool test_input_filter( Filter filter,
175                         const Source1& input,
176                         const Source2& output )
177 {
178     // Use tag dispatch to compensate for bad overload resolution.
179     return test_input_filter( filter, input, output,
180                               is_string<Source1>() );
181 }
182 
183 //--------------Definition of test_output_filter------------------------------//
184 
185 template<typename Filter>
test_output_filter(Filter filter,const std::string & input,const std::string & output,mpl::true_)186 bool test_output_filter( Filter filter,
187                          const std::string& input,
188                          const std::string& output,
189                          mpl::true_ )
190 {
191     for ( int inc = default_increment;
192           inc < default_increment * 40;
193           inc += default_increment )
194     {
195         array_source  src(input.data(), input.data() + input.size());
196         std::string   dest;
197         iostreams::copy(src, compose(filter, non_blocking_sink(dest, inc)));
198         if (dest != output )
199             return false;
200     }
201     return true;
202 }
203 
204 template<typename Filter, typename Source1, typename Source2>
test_output_filter(Filter filter,const Source1 & input,const Source2 & output,mpl::false_)205 bool test_output_filter( Filter filter,
206                          const Source1& input,
207                          const Source2& output,
208                          mpl::false_ )
209 {
210     std::string in;
211     std::string out;
212     iostreams::copy(input, iostreams::back_inserter(in));
213     iostreams::copy(output, iostreams::back_inserter(out));
214     return test_output_filter(filter, in, out);
215 }
216 
217 template<typename Filter, typename Source1, typename Source2>
test_output_filter(Filter filter,const Source1 & input,const Source2 & output)218 bool test_output_filter( Filter filter,
219                          const Source1& input,
220                          const Source2& output )
221 {
222     // Use tag dispatch to compensate for bad overload resolution.
223     return test_output_filter( filter, input, output,
224                                is_string<Source1>() );
225 }
226 
227 //--------------Definition of test_filter_pair--------------------------------//
228 
229 template<typename OutputFilter, typename InputFilter>
test_filter_pair(OutputFilter out,InputFilter in,const std::string & data,mpl::true_)230 bool test_filter_pair( OutputFilter out,
231                        InputFilter in,
232                        const std::string& data,
233                        mpl::true_ )
234 {
235     for ( int inc = default_increment;
236           inc <= default_increment * 40;
237           inc += default_increment )
238     {
239         {
240             array_source  src(data.data(), data.data() + data.size());
241             std::string   temp;
242             std::string   dest;
243             iostreams::copy(src, compose(out, non_blocking_sink(temp, inc)));
244             iostreams::copy(
245                 compose(in, non_blocking_source(temp, inc)),
246                 iostreams::back_inserter(dest)
247             );
248             if (dest != data)
249                 return false;
250         }
251         {
252             array_source  src(data.data(), data.data() + data.size());
253             std::string   temp;
254             std::string   dest;
255             iostreams::copy(src, compose(out, non_blocking_sink(temp, inc)));
256             // truncate the file, this should not loop, it may throw
257             // std::ios_base::failure, which we swallow.
258             try {
259                 temp.resize(temp.size() / 2);
260                 iostreams::copy(
261                     compose(in, non_blocking_source(temp, inc)),
262                     iostreams::back_inserter(dest)
263                 );
264             } catch(std::ios_base::failure&) {}
265         }
266         {
267             array_source  src(data.data(), data.data() + data.size());
268             std::string   temp;
269             std::string   dest;
270             iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
271             iostreams::copy(
272                 non_blocking_source(temp, inc),
273                 compose(in, iostreams::back_inserter(dest))
274             );
275             if (dest != data)
276                 return false;
277         }
278         {
279             array_source  src(data.data(), data.data() + data.size());
280             std::string   temp;
281             std::string   dest;
282             iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
283             // truncate the file, this should not loop, it may throw
284             // std::ios_base::failure, which we swallow.
285             try {
286                 temp.resize(temp.size() / 2);
287                 iostreams::copy(
288                     non_blocking_source(temp, inc),
289                     compose(in, iostreams::back_inserter(dest))
290                 );
291             } catch(std::ios_base::failure&) {}
292         }
293     }
294     return true;
295 }
296 
297 template<typename OutputFilter, typename InputFilter, typename Source>
test_filter_pair(OutputFilter out,InputFilter in,const Source & data,mpl::false_)298 bool test_filter_pair( OutputFilter out,
299                        InputFilter in,
300                        const Source& data,
301                        mpl::false_ )
302 {
303     std::string str;
304     iostreams::copy(data, iostreams::back_inserter(str));
305     return test_filter_pair(out, in, str);
306 }
307 
308 template<typename OutputFilter, typename InputFilter, typename Source>
test_filter_pair(OutputFilter out,InputFilter in,const Source & data)309 bool test_filter_pair( OutputFilter out,
310                        InputFilter in,
311                        const Source& data )
312 {
313     // Use tag dispatch to compensate for bad overload resolution.
314     return test_filter_pair(out, in, data, is_string<Source>());
315 }
316 
317 } } // End namespaces iostreams, boost.
318 
319 #endif // #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED
320