2016-10-18 19:43:36 -04:00
|
|
|
//
|
2017-07-24 09:42:36 -07:00
|
|
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2016-10-18 19:43:36 -04:00
|
|
|
//
|
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
//
|
2017-07-20 13:40:34 -07:00
|
|
|
// Official repository: https://github.com/boostorg/beast
|
|
|
|
|
//
|
2016-10-18 19:43:36 -04:00
|
|
|
|
|
|
|
|
// Test that header file is self-contained.
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/zlib/inflate_stream.hpp>
|
2016-10-18 19:43:36 -04:00
|
|
|
|
2017-07-31 18:40:14 -07:00
|
|
|
#include <boost/beast/core/string.hpp>
|
2018-11-11 14:07:55 -08:00
|
|
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
2016-10-18 19:43:36 -04:00
|
|
|
#include <chrono>
|
|
|
|
|
#include <random>
|
|
|
|
|
|
2017-08-01 16:48:10 -07:00
|
|
|
#include "zlib-1.2.11/zlib.h"
|
2017-07-31 18:40:14 -07:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
namespace boost {
|
2016-10-18 19:43:36 -04:00
|
|
|
namespace beast {
|
|
|
|
|
namespace zlib {
|
|
|
|
|
|
|
|
|
|
class inflate_stream_test : public beast::unit_test::suite
|
|
|
|
|
{
|
|
|
|
|
public:
|
2017-07-31 18:40:14 -07:00
|
|
|
// Lots of repeats, limited char range
|
|
|
|
|
static
|
|
|
|
|
std::string
|
|
|
|
|
corpus1(std::size_t n)
|
|
|
|
|
{
|
|
|
|
|
static std::string const alphabet{
|
|
|
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
};
|
|
|
|
|
std::string s;
|
|
|
|
|
s.reserve(n + 5);
|
|
|
|
|
std::mt19937 g;
|
|
|
|
|
std::uniform_int_distribution<std::size_t> d0{
|
|
|
|
|
0, alphabet.size() - 1};
|
|
|
|
|
std::uniform_int_distribution<std::size_t> d1{
|
|
|
|
|
1, 5};
|
|
|
|
|
while(s.size() < n)
|
|
|
|
|
{
|
|
|
|
|
auto const rep = d1(g);
|
|
|
|
|
auto const ch = alphabet[d0(g)];
|
|
|
|
|
s.insert(s.end(), rep, ch);
|
|
|
|
|
}
|
|
|
|
|
s.resize(n);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Random data
|
|
|
|
|
static
|
|
|
|
|
std::string
|
|
|
|
|
corpus2(std::size_t n)
|
|
|
|
|
{
|
|
|
|
|
std::string s;
|
|
|
|
|
s.reserve(n);
|
|
|
|
|
std::mt19937 g;
|
|
|
|
|
std::uniform_int_distribution<std::uint32_t> d0{0, 255};
|
|
|
|
|
while(n--)
|
|
|
|
|
s.push_back(static_cast<char>(d0(g)));
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
|
std::string
|
|
|
|
|
compress(
|
|
|
|
|
string_view const& in,
|
|
|
|
|
int level, // 0=none, 1..9, -1=default
|
|
|
|
|
int windowBits, // 9..15
|
|
|
|
|
int memLevel, // 1..9 (8=default)
|
|
|
|
|
int strategy) // e.g. Z_DEFAULT_STRATEGY
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
z_stream zs;
|
|
|
|
|
memset(&zs, 0, sizeof(zs));
|
|
|
|
|
result = deflateInit2(
|
|
|
|
|
&zs,
|
|
|
|
|
level,
|
|
|
|
|
Z_DEFLATED,
|
|
|
|
|
-windowBits,
|
|
|
|
|
memLevel,
|
|
|
|
|
strategy);
|
|
|
|
|
if(result != Z_OK)
|
|
|
|
|
throw std::logic_error{"deflateInit2 failed"};
|
|
|
|
|
zs.next_in = (Bytef*)in.data();
|
|
|
|
|
zs.avail_in = static_cast<uInt>(in.size());
|
|
|
|
|
std::string out;
|
|
|
|
|
out.resize(deflateBound(&zs,
|
|
|
|
|
static_cast<uLong>(in.size())));
|
|
|
|
|
zs.next_in = (Bytef*)in.data();
|
|
|
|
|
zs.avail_in = static_cast<uInt>(in.size());
|
|
|
|
|
zs.next_out = (Bytef*)&out[0];
|
|
|
|
|
zs.avail_out = static_cast<uInt>(out.size());
|
|
|
|
|
result = deflate(&zs, Z_FULL_FLUSH);
|
|
|
|
|
if(result != Z_OK)
|
|
|
|
|
throw std::logic_error("deflate failed");
|
|
|
|
|
out.resize(zs.total_out);
|
|
|
|
|
deflateEnd(&zs);
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 19:43:36 -04:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
enum Split
|
|
|
|
|
{
|
|
|
|
|
once,
|
|
|
|
|
half,
|
|
|
|
|
full
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Beast
|
|
|
|
|
{
|
|
|
|
|
Split in_;
|
|
|
|
|
Split check_;
|
|
|
|
|
Flush flush_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Beast(Split in, Split check, Flush flush = Flush::sync)
|
|
|
|
|
: in_(in)
|
|
|
|
|
, check_(check)
|
|
|
|
|
, flush_(flush)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
operator()(
|
|
|
|
|
int window,
|
|
|
|
|
std::string const& in,
|
|
|
|
|
std::string const& check,
|
|
|
|
|
unit_test::suite& suite) const
|
|
|
|
|
{
|
|
|
|
|
auto const f =
|
|
|
|
|
[&](std::size_t i, std::size_t j)
|
|
|
|
|
{
|
|
|
|
|
std::string out(check.size(), 0);
|
|
|
|
|
z_params zs;
|
|
|
|
|
zs.next_in = in.data();
|
|
|
|
|
zs.next_out = &out[0];
|
|
|
|
|
zs.avail_in = i;
|
|
|
|
|
zs.avail_out = j;
|
|
|
|
|
inflate_stream is;
|
|
|
|
|
is.reset(window);
|
|
|
|
|
bool bi = ! (i < in.size());
|
|
|
|
|
bool bo = ! (j < check.size());
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
is.write(zs, flush_, ec);
|
|
|
|
|
if( ec == error::need_buffers ||
|
|
|
|
|
ec == error::end_of_stream)
|
|
|
|
|
{
|
|
|
|
|
out.resize(zs.total_out);
|
|
|
|
|
suite.expect(out == check, __FILE__, __LINE__);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(ec)
|
|
|
|
|
{
|
|
|
|
|
suite.fail(ec.message(), __FILE__, __LINE__);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(zs.avail_in == 0 && ! bi)
|
|
|
|
|
{
|
|
|
|
|
bi = true;
|
|
|
|
|
zs.avail_in = in.size() - i;
|
|
|
|
|
}
|
|
|
|
|
if(zs.avail_out == 0 && ! bo)
|
|
|
|
|
{
|
|
|
|
|
bo = true;
|
|
|
|
|
zs.avail_out = check.size() - j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::size_t i0, i1;
|
|
|
|
|
std::size_t j0, j1;
|
|
|
|
|
|
|
|
|
|
switch(in_)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
case once: i0 = in.size(); i1 = i0; break;
|
|
|
|
|
case half: i0 = in.size() / 2; i1 = i0; break;
|
|
|
|
|
case full: i0 = 1; i1 = in.size(); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(check_)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
case once: j0 = check.size(); j1 = j0; break;
|
|
|
|
|
case half: j0 = check.size() / 2; j1 = j0; break;
|
|
|
|
|
case full: j0 = 1; j1 = check.size(); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(std::size_t i = i0; i <= i1; ++i)
|
|
|
|
|
for(std::size_t j = j0; j <= j1; ++j)
|
|
|
|
|
f(i, j);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Matrix
|
|
|
|
|
{
|
|
|
|
|
unit_test::suite& suite_;
|
|
|
|
|
|
|
|
|
|
int level_[2];
|
|
|
|
|
int window_[2];
|
|
|
|
|
int strategy_[2];
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit
|
|
|
|
|
Matrix(unit_test::suite& suite)
|
|
|
|
|
: suite_(suite)
|
|
|
|
|
{
|
|
|
|
|
level_[0] = 0;
|
|
|
|
|
level_[1] = 9;
|
2017-07-12 14:22:15 -07:00
|
|
|
window_[0] = 9;
|
2016-10-18 19:43:36 -04:00
|
|
|
window_[1] = 15;
|
|
|
|
|
strategy_[0] = 0;
|
|
|
|
|
strategy_[1] = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
level(int from, int to)
|
|
|
|
|
{
|
|
|
|
|
level_[0] = from;
|
|
|
|
|
level_[1] = to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
level(int what)
|
|
|
|
|
{
|
|
|
|
|
level(what, what);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
window(int from, int to)
|
|
|
|
|
{
|
|
|
|
|
window_[0] = from;
|
|
|
|
|
window_[1] = to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
window(int what)
|
|
|
|
|
{
|
|
|
|
|
window(what, what);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
strategy(int from, int to)
|
|
|
|
|
{
|
|
|
|
|
strategy_[0] = from;
|
|
|
|
|
strategy_[1] = to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
strategy(int what)
|
|
|
|
|
{
|
|
|
|
|
strategy(what, what);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class F>
|
|
|
|
|
void
|
|
|
|
|
operator()(
|
|
|
|
|
F const& f,
|
|
|
|
|
std::string const& check) const
|
|
|
|
|
{
|
|
|
|
|
for(auto level = level_[0];
|
|
|
|
|
level <= level_[1]; ++level)
|
|
|
|
|
{
|
|
|
|
|
for(auto window = window_[0];
|
|
|
|
|
window <= window_[1]; ++window)
|
|
|
|
|
{
|
|
|
|
|
for(auto strategy = strategy_[0];
|
|
|
|
|
strategy <= strategy_[1]; ++strategy)
|
2017-07-31 18:40:14 -07:00
|
|
|
f(
|
|
|
|
|
window,
|
|
|
|
|
compress(check, level, window, 4, strategy),
|
|
|
|
|
check,
|
|
|
|
|
suite_);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testInflate()
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
|
|
|
|
std::string check =
|
|
|
|
|
"{\n \"AutobahnPython/0.6.0\": {\n"
|
|
|
|
|
" \"1.1.1\": {\n"
|
|
|
|
|
" \"behavior\": \"OK\",\n"
|
|
|
|
|
" \"behaviorClose\": \"OK\",\n"
|
|
|
|
|
" \"duration\": 2,\n"
|
|
|
|
|
" \"remoteCloseCode\": 1000,\n"
|
|
|
|
|
" \"reportfile\": \"autobahnpython_0_6_0_case_1_1_1.json\"\n"
|
|
|
|
|
;
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{half, half}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
2017-06-19 08:34:14 -07:00
|
|
|
|
2016-10-18 19:43:36 -04:00
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
2017-07-31 18:40:14 -07:00
|
|
|
auto const check = corpus1(5000);
|
|
|
|
|
m(Beast{half, half}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
2017-07-31 18:40:14 -07:00
|
|
|
auto const check = corpus2(5000);
|
|
|
|
|
m(Beast{half, half}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
2017-07-31 18:40:14 -07:00
|
|
|
auto const check = corpus1(1000);
|
2016-10-18 19:43:36 -04:00
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
m.strategy(Z_DEFAULT_STRATEGY);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{once, full}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
2017-07-31 18:40:14 -07:00
|
|
|
auto const check = corpus2(1000);
|
2016-10-18 19:43:36 -04:00
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
m.strategy(Z_DEFAULT_STRATEGY);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{once, full}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
|
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
auto const check = corpus1(200);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{full, full}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
|
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
auto const check = corpus2(500);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{full, full}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
2017-07-31 18:40:14 -07:00
|
|
|
auto const check = corpus2(1000);
|
2016-10-18 19:43:36 -04:00
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
m.strategy(Z_DEFAULT_STRATEGY);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{full, once, Flush::block}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VFALCO Fails, but I'm unsure of what the correct
|
|
|
|
|
// behavior of Z_TREES/Flush::trees is.
|
|
|
|
|
#if 0
|
|
|
|
|
{
|
|
|
|
|
Matrix m{*this};
|
|
|
|
|
auto const check = corpus2(10000);
|
|
|
|
|
m.level(6);
|
|
|
|
|
m.window(9);
|
|
|
|
|
m.strategy(Z_DEFAULT_STRATEGY);
|
2017-07-31 18:40:14 -07:00
|
|
|
m(Beast{full, once, Flush::trees}, check);
|
2016-10-18 19:43:36 -04:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
run() override
|
|
|
|
|
{
|
|
|
|
|
log <<
|
|
|
|
|
"sizeof(inflate_stream) == " <<
|
|
|
|
|
sizeof(inflate_stream) << std::endl;
|
|
|
|
|
testInflate();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 17:01:57 -07:00
|
|
|
BEAST_DEFINE_TESTSUITE(beast,zlib,inflate_stream);
|
2016-10-18 19:43:36 -04:00
|
|
|
|
|
|
|
|
} // zlib
|
|
|
|
|
} // beast
|
2017-07-20 13:40:34 -07:00
|
|
|
} // boost
|