]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | ||
8 | // Test that header file is self-contained. | |
9 | #include <beast/zlib/deflate_stream.hpp> | |
10 | ||
11 | #include "ztest.hpp" | |
12 | #include <beast/unit_test/suite.hpp> | |
13 | ||
14 | namespace beast { | |
15 | namespace zlib { | |
16 | ||
17 | class deflate_stream_test : public beast::unit_test::suite | |
18 | { | |
19 | public: | |
20 | using self = deflate_stream_test; | |
21 | typedef void(self::*pmf_t)( | |
22 | int level, int windowBits, int strategy, | |
23 | std::string const&); | |
24 | ||
25 | static | |
26 | Strategy | |
27 | toStrategy(int strategy) | |
28 | { | |
29 | switch(strategy) | |
30 | { | |
31 | default: | |
32 | case 0: return Strategy::normal; | |
33 | case 1: return Strategy::filtered; | |
34 | case 2: return Strategy::huffman; | |
35 | case 3: return Strategy::rle; | |
36 | case 4: return Strategy::fixed; | |
37 | } | |
38 | } | |
39 | ||
40 | void | |
41 | doDeflate1_zlib( | |
42 | int level, int windowBits, int strategy, | |
43 | std::string const& check) | |
44 | { | |
45 | int result; | |
46 | std::string out; | |
47 | ::z_stream zs; | |
48 | std::memset(&zs, 0, sizeof(zs)); | |
49 | result = deflateInit2(&zs, | |
50 | level, | |
51 | Z_DEFLATED, | |
52 | -windowBits, | |
53 | 8, | |
54 | strategy); | |
55 | if(! BEAST_EXPECT(result == Z_OK)) | |
56 | goto err; | |
57 | out.resize(deflateBound(&zs, | |
58 | static_cast<uLong>(check.size()))); | |
59 | zs.next_in = (Bytef*)check.data(); | |
60 | zs.avail_in = static_cast<uInt>(check.size()); | |
61 | zs.next_out = (Bytef*)out.data(); | |
62 | zs.avail_out = static_cast<uInt>(out.size()); | |
63 | { | |
64 | bool progress = true; | |
65 | for(;;) | |
66 | { | |
67 | result = deflate(&zs, Z_FULL_FLUSH); | |
68 | if( result == Z_BUF_ERROR || | |
69 | result == Z_STREAM_END) // per zlib FAQ | |
70 | goto fin; | |
71 | if(! BEAST_EXPECT(progress)) | |
72 | goto err; | |
73 | progress = false; | |
74 | } | |
75 | } | |
76 | ||
77 | fin: | |
78 | out.resize(zs.total_out); | |
79 | { | |
80 | z_inflator zi; | |
81 | auto const s = zi(out); | |
82 | BEAST_EXPECT(s == check); | |
83 | } | |
84 | ||
85 | err: | |
86 | deflateEnd(&zs); | |
87 | } | |
88 | ||
89 | void | |
90 | doDeflate1_beast( | |
91 | int level, int windowBits, int strategy, | |
92 | std::string const& check) | |
93 | { | |
94 | std::string out; | |
95 | z_params zs; | |
96 | deflate_stream ds; | |
97 | ds.reset( | |
98 | level, | |
99 | windowBits, | |
100 | 8, | |
101 | toStrategy(strategy)); | |
102 | out.resize(ds.upper_bound( | |
103 | static_cast<uLong>(check.size()))); | |
104 | zs.next_in = (Bytef*)check.data(); | |
105 | zs.avail_in = static_cast<uInt>(check.size()); | |
106 | zs.next_out = (Bytef*)out.data(); | |
107 | zs.avail_out = static_cast<uInt>(out.size()); | |
108 | { | |
109 | bool progress = true; | |
110 | for(;;) | |
111 | { | |
112 | error_code ec; | |
113 | ds.write(zs, Flush::full, ec); | |
114 | if( ec == error::need_buffers || | |
115 | ec == error::end_of_stream) // per zlib FAQ | |
116 | goto fin; | |
117 | if(! BEAST_EXPECTS(! ec, ec.message())) | |
118 | goto err; | |
119 | if(! BEAST_EXPECT(progress)) | |
120 | goto err; | |
121 | progress = false; | |
122 | } | |
123 | } | |
124 | ||
125 | fin: | |
126 | out.resize(zs.total_out); | |
127 | { | |
128 | z_inflator zi; | |
129 | auto const s = zi(out); | |
130 | BEAST_EXPECT(s == check); | |
131 | } | |
132 | ||
133 | err: | |
134 | ; | |
135 | } | |
136 | ||
137 | //-------------------------------------------------------------------------- | |
138 | ||
139 | void | |
140 | doDeflate2_zlib( | |
141 | int level, int windowBits, int strategy, | |
142 | std::string const& check) | |
143 | { | |
144 | for(std::size_t i = 1; i < check.size(); ++i) | |
145 | { | |
146 | for(std::size_t j = 1;; ++j) | |
147 | { | |
148 | int result; | |
149 | ::z_stream zs; | |
150 | std::memset(&zs, 0, sizeof(zs)); | |
151 | result = deflateInit2(&zs, | |
152 | level, | |
153 | Z_DEFLATED, | |
154 | -windowBits, | |
155 | 8, | |
156 | strategy); | |
157 | if(! BEAST_EXPECT(result == Z_OK)) | |
158 | continue; | |
159 | std::string out; | |
160 | out.resize(deflateBound(&zs, | |
161 | static_cast<uLong>(check.size()))); | |
162 | if(j >= out.size()) | |
163 | { | |
164 | deflateEnd(&zs); | |
165 | break; | |
166 | } | |
167 | zs.next_in = (Bytef*)check.data(); | |
168 | zs.avail_in = static_cast<uInt>(i); | |
169 | zs.next_out = (Bytef*)out.data(); | |
170 | zs.avail_out = static_cast<uInt>(j); | |
171 | bool bi = false; | |
172 | bool bo = false; | |
173 | for(;;) | |
174 | { | |
175 | int flush = bi ? Z_FULL_FLUSH : Z_NO_FLUSH; | |
176 | result = deflate(&zs, flush); | |
177 | if( result == Z_BUF_ERROR || | |
178 | result == Z_STREAM_END) // per zlib FAQ | |
179 | goto fin; | |
180 | if(! BEAST_EXPECT(result == Z_OK)) | |
181 | goto err; | |
182 | if(zs.avail_in == 0 && ! bi) | |
183 | { | |
184 | bi = true; | |
185 | zs.avail_in = | |
186 | static_cast<uInt>(check.size() - i); | |
187 | } | |
188 | if(zs.avail_out == 0 && ! bo) | |
189 | { | |
190 | bo = true; | |
191 | zs.avail_out = | |
192 | static_cast<uInt>(out.size() - j); | |
193 | } | |
194 | } | |
195 | ||
196 | fin: | |
197 | out.resize(zs.total_out); | |
198 | { | |
199 | z_inflator zi; | |
200 | auto const s = zi(out); | |
201 | BEAST_EXPECT(s == check); | |
202 | } | |
203 | ||
204 | err: | |
205 | deflateEnd(&zs); | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | void | |
211 | doDeflate2_beast( | |
212 | int level, int windowBits, int strategy, | |
213 | std::string const& check) | |
214 | { | |
215 | for(std::size_t i = 1; i < check.size(); ++i) | |
216 | { | |
217 | for(std::size_t j = 1;; ++j) | |
218 | { | |
219 | z_params zs; | |
220 | deflate_stream ds; | |
221 | ds.reset( | |
222 | level, | |
223 | windowBits, | |
224 | 8, | |
225 | toStrategy(strategy)); | |
226 | std::string out; | |
227 | out.resize(ds.upper_bound( | |
228 | static_cast<uLong>(check.size()))); | |
229 | if(j >= out.size()) | |
230 | break; | |
231 | zs.next_in = (Bytef*)check.data(); | |
232 | zs.avail_in = static_cast<uInt>(i); | |
233 | zs.next_out = (Bytef*)out.data(); | |
234 | zs.avail_out = static_cast<uInt>(j); | |
235 | bool bi = false; | |
236 | bool bo = false; | |
237 | for(;;) | |
238 | { | |
239 | error_code ec; | |
240 | ds.write(zs, | |
241 | bi ? Flush::full : Flush::none, ec); | |
242 | if( ec == error::need_buffers || | |
243 | ec == error::end_of_stream) // per zlib FAQ | |
244 | goto fin; | |
245 | if(! BEAST_EXPECTS(! ec, ec.message())) | |
246 | goto err; | |
247 | if(zs.avail_in == 0 && ! bi) | |
248 | { | |
249 | bi = true; | |
250 | zs.avail_in = | |
251 | static_cast<uInt>(check.size() - i); | |
252 | } | |
253 | if(zs.avail_out == 0 && ! bo) | |
254 | { | |
255 | bo = true; | |
256 | zs.avail_out = | |
257 | static_cast<uInt>(out.size() - j); | |
258 | } | |
259 | } | |
260 | ||
261 | fin: | |
262 | out.resize(zs.total_out); | |
263 | { | |
264 | z_inflator zi; | |
265 | auto const s = zi(out); | |
266 | BEAST_EXPECT(s == check); | |
267 | } | |
268 | ||
269 | err: | |
270 | ; | |
271 | } | |
272 | } | |
273 | } | |
274 | ||
275 | //-------------------------------------------------------------------------- | |
276 | ||
277 | void | |
278 | doMatrix(std::string const& label, | |
279 | std::string const& check, pmf_t pmf) | |
280 | { | |
281 | using namespace std::chrono; | |
282 | using clock_type = steady_clock; | |
283 | auto const when = clock_type::now(); | |
284 | for(int level = 0; level <= 9; ++level) | |
285 | { | |
286 | for(int windowBits = 8; windowBits <= 9; ++windowBits) | |
287 | { | |
288 | for(int strategy = 0; strategy <= 4; ++strategy) | |
289 | { | |
290 | (this->*pmf)( | |
291 | level, windowBits, strategy, check); | |
292 | } | |
293 | } | |
294 | } | |
295 | auto const elapsed = clock_type::now() - when; | |
296 | log << | |
297 | label << ": " << | |
298 | duration_cast< | |
299 | milliseconds>(elapsed).count() << "ms\n"; | |
300 | log.flush(); | |
301 | } | |
302 | ||
303 | void | |
304 | testDeflate() | |
305 | { | |
306 | doMatrix("1.beast ", "Hello, world!", &self::doDeflate1_beast); | |
307 | doMatrix("1.zlib ", "Hello, world!", &self::doDeflate1_zlib); | |
308 | doMatrix("2.beast ", "Hello, world!", &self::doDeflate2_beast); | |
309 | doMatrix("2.zlib ", "Hello, world!", &self::doDeflate2_zlib); | |
310 | { | |
311 | auto const s = corpus1(56); | |
312 | doMatrix("3.beast ", s, &self::doDeflate2_beast); | |
313 | doMatrix("3.zlib ", s, &self::doDeflate2_zlib); | |
314 | } | |
315 | { | |
316 | auto const s = corpus1(512 * 1024); | |
317 | doMatrix("4.beast ", s, &self::doDeflate1_beast); | |
318 | doMatrix("4.zlib ", s, &self::doDeflate1_zlib); | |
319 | } | |
320 | } | |
321 | ||
322 | void | |
323 | run() override | |
324 | { | |
325 | log << | |
326 | "sizeof(deflate_stream) == " << | |
327 | sizeof(deflate_stream) << std::endl; | |
328 | ||
329 | testDeflate(); | |
330 | } | |
331 | }; | |
332 | ||
333 | BEAST_DEFINE_TESTSUITE(deflate_stream,core,beast); | |
334 | ||
335 | } // zlib | |
336 | } // beast |