test.hpp 10 KB

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