]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // |
b32b8144 | 2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) |
7c673cae FG |
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 | // | |
b32b8144 FG |
7 | // Official repository: https://github.com/boostorg/beast |
8 | // | |
7c673cae FG |
9 | |
10 | // Test that header file is self-contained. | |
b32b8144 | 11 | #include <boost/beast/zlib/inflate_stream.hpp> |
7c673cae | 12 | |
b32b8144 FG |
13 | #include <boost/beast/core/string.hpp> |
14 | #include <boost/beast/unit_test/suite.hpp> | |
7c673cae FG |
15 | #include <chrono> |
16 | #include <random> | |
17 | ||
b32b8144 FG |
18 | #include "zlib-1.2.11/zlib.h" |
19 | ||
20 | namespace boost { | |
7c673cae FG |
21 | namespace beast { |
22 | namespace zlib { | |
23 | ||
24 | class inflate_stream_test : public beast::unit_test::suite | |
25 | { | |
26 | public: | |
b32b8144 FG |
27 | // Lots of repeats, limited char range |
28 | static | |
29 | std::string | |
30 | corpus1(std::size_t n) | |
31 | { | |
32 | static std::string const alphabet{ | |
33 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | |
34 | }; | |
35 | std::string s; | |
36 | s.reserve(n + 5); | |
37 | std::mt19937 g; | |
38 | std::uniform_int_distribution<std::size_t> d0{ | |
39 | 0, alphabet.size() - 1}; | |
40 | std::uniform_int_distribution<std::size_t> d1{ | |
41 | 1, 5}; | |
42 | while(s.size() < n) | |
43 | { | |
44 | auto const rep = d1(g); | |
45 | auto const ch = alphabet[d0(g)]; | |
46 | s.insert(s.end(), rep, ch); | |
47 | } | |
48 | s.resize(n); | |
49 | return s; | |
50 | } | |
51 | ||
52 | // Random data | |
53 | static | |
54 | std::string | |
55 | corpus2(std::size_t n) | |
56 | { | |
57 | std::string s; | |
58 | s.reserve(n); | |
59 | std::mt19937 g; | |
60 | std::uniform_int_distribution<std::uint32_t> d0{0, 255}; | |
61 | while(n--) | |
62 | s.push_back(static_cast<char>(d0(g))); | |
63 | return s; | |
64 | } | |
65 | ||
66 | static | |
67 | std::string | |
68 | compress( | |
69 | string_view const& in, | |
70 | int level, // 0=none, 1..9, -1=default | |
71 | int windowBits, // 9..15 | |
72 | int memLevel, // 1..9 (8=default) | |
73 | int strategy) // e.g. Z_DEFAULT_STRATEGY | |
74 | { | |
75 | int result; | |
76 | z_stream zs; | |
77 | memset(&zs, 0, sizeof(zs)); | |
78 | result = deflateInit2( | |
79 | &zs, | |
80 | level, | |
81 | Z_DEFLATED, | |
82 | -windowBits, | |
83 | memLevel, | |
84 | strategy); | |
85 | if(result != Z_OK) | |
86 | throw std::logic_error{"deflateInit2 failed"}; | |
87 | zs.next_in = (Bytef*)in.data(); | |
88 | zs.avail_in = static_cast<uInt>(in.size()); | |
89 | std::string out; | |
90 | out.resize(deflateBound(&zs, | |
91 | static_cast<uLong>(in.size()))); | |
92 | zs.next_in = (Bytef*)in.data(); | |
93 | zs.avail_in = static_cast<uInt>(in.size()); | |
94 | zs.next_out = (Bytef*)&out[0]; | |
95 | zs.avail_out = static_cast<uInt>(out.size()); | |
96 | result = deflate(&zs, Z_FULL_FLUSH); | |
97 | if(result != Z_OK) | |
98 | throw std::logic_error("deflate failed"); | |
99 | out.resize(zs.total_out); | |
100 | deflateEnd(&zs); | |
101 | return out; | |
102 | } | |
103 | ||
7c673cae FG |
104 | //-------------------------------------------------------------------------- |
105 | ||
106 | enum Split | |
107 | { | |
108 | once, | |
109 | half, | |
110 | full | |
111 | }; | |
112 | ||
113 | class Beast | |
114 | { | |
115 | Split in_; | |
116 | Split check_; | |
117 | Flush flush_; | |
118 | ||
119 | public: | |
120 | Beast(Split in, Split check, Flush flush = Flush::sync) | |
121 | : in_(in) | |
122 | , check_(check) | |
123 | , flush_(flush) | |
124 | { | |
125 | } | |
126 | ||
127 | void | |
128 | operator()( | |
129 | int window, | |
130 | std::string const& in, | |
131 | std::string const& check, | |
132 | unit_test::suite& suite) const | |
133 | { | |
134 | auto const f = | |
135 | [&](std::size_t i, std::size_t j) | |
136 | { | |
137 | std::string out(check.size(), 0); | |
138 | z_params zs; | |
139 | zs.next_in = in.data(); | |
140 | zs.next_out = &out[0]; | |
141 | zs.avail_in = i; | |
142 | zs.avail_out = j; | |
143 | inflate_stream is; | |
144 | is.reset(window); | |
145 | bool bi = ! (i < in.size()); | |
146 | bool bo = ! (j < check.size()); | |
147 | for(;;) | |
148 | { | |
149 | error_code ec; | |
150 | is.write(zs, flush_, ec); | |
151 | if( ec == error::need_buffers || | |
152 | ec == error::end_of_stream) | |
153 | { | |
154 | out.resize(zs.total_out); | |
155 | suite.expect(out == check, __FILE__, __LINE__); | |
156 | break; | |
157 | } | |
158 | if(ec) | |
159 | { | |
160 | suite.fail(ec.message(), __FILE__, __LINE__); | |
161 | break; | |
162 | } | |
163 | if(zs.avail_in == 0 && ! bi) | |
164 | { | |
165 | bi = true; | |
166 | zs.avail_in = in.size() - i; | |
167 | } | |
168 | if(zs.avail_out == 0 && ! bo) | |
169 | { | |
170 | bo = true; | |
171 | zs.avail_out = check.size() - j; | |
172 | } | |
173 | } | |
174 | }; | |
175 | ||
176 | std::size_t i0, i1; | |
177 | std::size_t j0, j1; | |
178 | ||
179 | switch(in_) | |
180 | { | |
181 | default: | |
182 | case once: i0 = in.size(); i1 = i0; break; | |
183 | case half: i0 = in.size() / 2; i1 = i0; break; | |
184 | case full: i0 = 1; i1 = in.size(); break; | |
185 | } | |
186 | ||
187 | switch(check_) | |
188 | { | |
189 | default: | |
190 | case once: j0 = check.size(); j1 = j0; break; | |
191 | case half: j0 = check.size() / 2; j1 = j0; break; | |
192 | case full: j0 = 1; j1 = check.size(); break; | |
193 | } | |
194 | ||
195 | for(std::size_t i = i0; i <= i1; ++i) | |
196 | for(std::size_t j = j0; j <= j1; ++j) | |
197 | f(i, j); | |
198 | } | |
199 | }; | |
200 | ||
7c673cae FG |
201 | class Matrix |
202 | { | |
203 | unit_test::suite& suite_; | |
204 | ||
205 | int level_[2]; | |
206 | int window_[2]; | |
207 | int strategy_[2]; | |
208 | ||
209 | public: | |
210 | explicit | |
211 | Matrix(unit_test::suite& suite) | |
212 | : suite_(suite) | |
213 | { | |
214 | level_[0] = 0; | |
215 | level_[1] = 9; | |
b32b8144 | 216 | window_[0] = 9; |
7c673cae FG |
217 | window_[1] = 15; |
218 | strategy_[0] = 0; | |
219 | strategy_[1] = 4; | |
220 | } | |
221 | ||
222 | void | |
223 | level(int from, int to) | |
224 | { | |
225 | level_[0] = from; | |
226 | level_[1] = to; | |
227 | } | |
228 | ||
229 | void | |
230 | level(int what) | |
231 | { | |
232 | level(what, what); | |
233 | } | |
234 | ||
235 | void | |
236 | window(int from, int to) | |
237 | { | |
238 | window_[0] = from; | |
239 | window_[1] = to; | |
240 | } | |
241 | ||
242 | void | |
243 | window(int what) | |
244 | { | |
245 | window(what, what); | |
246 | } | |
247 | ||
248 | void | |
249 | strategy(int from, int to) | |
250 | { | |
251 | strategy_[0] = from; | |
252 | strategy_[1] = to; | |
253 | } | |
254 | ||
255 | void | |
256 | strategy(int what) | |
257 | { | |
258 | strategy(what, what); | |
259 | } | |
260 | ||
261 | template<class F> | |
262 | void | |
263 | operator()( | |
7c673cae FG |
264 | F const& f, |
265 | std::string const& check) const | |
266 | { | |
7c673cae FG |
267 | for(auto level = level_[0]; |
268 | level <= level_[1]; ++level) | |
269 | { | |
270 | for(auto window = window_[0]; | |
271 | window <= window_[1]; ++window) | |
272 | { | |
273 | for(auto strategy = strategy_[0]; | |
274 | strategy <= strategy_[1]; ++strategy) | |
b32b8144 FG |
275 | f( |
276 | window, | |
277 | compress(check, level, window, 4, strategy), | |
278 | check, | |
279 | suite_); | |
7c673cae FG |
280 | } |
281 | } | |
7c673cae FG |
282 | } |
283 | }; | |
284 | ||
285 | void | |
286 | testInflate() | |
287 | { | |
288 | { | |
289 | Matrix m{*this}; | |
290 | std::string check = | |
291 | "{\n \"AutobahnPython/0.6.0\": {\n" | |
292 | " \"1.1.1\": {\n" | |
293 | " \"behavior\": \"OK\",\n" | |
294 | " \"behaviorClose\": \"OK\",\n" | |
295 | " \"duration\": 2,\n" | |
296 | " \"remoteCloseCode\": 1000,\n" | |
297 | " \"reportfile\": \"autobahnpython_0_6_0_case_1_1_1.json\"\n" | |
298 | ; | |
b32b8144 | 299 | m(Beast{half, half}, check); |
7c673cae | 300 | } |
b32b8144 | 301 | |
7c673cae FG |
302 | { |
303 | Matrix m{*this}; | |
b32b8144 FG |
304 | auto const check = corpus1(5000); |
305 | m(Beast{half, half}, check); | |
7c673cae FG |
306 | } |
307 | { | |
308 | Matrix m{*this}; | |
b32b8144 FG |
309 | auto const check = corpus2(5000); |
310 | m(Beast{half, half}, check); | |
7c673cae FG |
311 | } |
312 | { | |
313 | Matrix m{*this}; | |
b32b8144 | 314 | auto const check = corpus1(1000); |
7c673cae FG |
315 | m.level(6); |
316 | m.window(9); | |
317 | m.strategy(Z_DEFAULT_STRATEGY); | |
b32b8144 | 318 | m(Beast{once, full}, check); |
7c673cae FG |
319 | } |
320 | { | |
321 | Matrix m{*this}; | |
b32b8144 | 322 | auto const check = corpus2(1000); |
7c673cae FG |
323 | m.level(6); |
324 | m.window(9); | |
325 | m.strategy(Z_DEFAULT_STRATEGY); | |
b32b8144 | 326 | m(Beast{once, full}, check); |
7c673cae FG |
327 | } |
328 | { | |
329 | Matrix m{*this}; | |
330 | m.level(6); | |
331 | m.window(9); | |
332 | auto const check = corpus1(200); | |
b32b8144 | 333 | m(Beast{full, full}, check); |
7c673cae FG |
334 | } |
335 | { | |
336 | Matrix m{*this}; | |
337 | m.level(6); | |
338 | m.window(9); | |
339 | auto const check = corpus2(500); | |
b32b8144 | 340 | m(Beast{full, full}, check); |
7c673cae FG |
341 | } |
342 | { | |
343 | Matrix m{*this}; | |
b32b8144 | 344 | auto const check = corpus2(1000); |
7c673cae FG |
345 | m.level(6); |
346 | m.window(9); | |
347 | m.strategy(Z_DEFAULT_STRATEGY); | |
b32b8144 | 348 | m(Beast{full, once, Flush::block}, check); |
7c673cae FG |
349 | } |
350 | ||
351 | // VFALCO Fails, but I'm unsure of what the correct | |
352 | // behavior of Z_TREES/Flush::trees is. | |
353 | #if 0 | |
354 | { | |
355 | Matrix m{*this}; | |
356 | auto const check = corpus2(10000); | |
357 | m.level(6); | |
358 | m.window(9); | |
359 | m.strategy(Z_DEFAULT_STRATEGY); | |
b32b8144 | 360 | m(Beast{full, once, Flush::trees}, check); |
7c673cae FG |
361 | } |
362 | #endif | |
363 | } | |
364 | ||
365 | void | |
366 | run() override | |
367 | { | |
368 | log << | |
369 | "sizeof(inflate_stream) == " << | |
370 | sizeof(inflate_stream) << std::endl; | |
371 | testInflate(); | |
372 | } | |
373 | }; | |
374 | ||
b32b8144 | 375 | BEAST_DEFINE_TESTSUITE(beast,zlib,inflate_stream); |
7c673cae FG |
376 | |
377 | } // zlib | |
378 | } // beast | |
b32b8144 | 379 | } // boost |