1// (C) COPYRIGHT 2017 ARM Limited
2// Based on gzip_test.cpp by:
3// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
4// (C) Copyright 2004-2007 Jonathan Turkanis
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
7
8// See http://www.boost.org/libs/iostreams for documentation.
9
10// Note: basically a copy-paste of the gzip test
11
12#include <cstddef>
13#include <string>
14#include <boost/iostreams/copy.hpp>
15#include <boost/iostreams/device/array.hpp>
16#include <boost/iostreams/device/back_inserter.hpp>
17#include <boost/iostreams/filter/lzma.hpp>
18#include <boost/iostreams/filter/test.hpp>
19#include <boost/iostreams/filtering_stream.hpp>
20#include <boost/ref.hpp>
21#include <boost/range/iterator_range.hpp>
22#include <boost/test/test_tools.hpp>
23#include <boost/test/unit_test.hpp>
24#include "detail/sequence.hpp"
25#include "detail/verification.hpp"
26
27using namespace boost;
28using namespace boost::iostreams;
29using namespace boost::iostreams::test;
30namespace io = boost::iostreams;
31using boost::unit_test::test_suite;
32
33template<class T> struct basic_test_alloc: std::allocator<T>
34{
35 basic_test_alloc()
36 {
37 }
38
39 basic_test_alloc( basic_test_alloc const& /*other*/ )
40 {
41 }
42
43 template<class U>
44 basic_test_alloc( basic_test_alloc<U> const & /*other*/ )
45 {
46 }
47
48 template<class U> struct rebind
49 {
50 typedef basic_test_alloc<U> other;
51 };
52};
53
54typedef basic_test_alloc<char> lzma_alloc;
55
56void compression_test()
57{
58 text_sequence data;
59
60 // Test compression and decompression with custom allocator
61 BOOST_CHECK(
62 test_filter_pair( basic_lzma_compressor<lzma_alloc>(),
63 basic_lzma_decompressor<lzma_alloc>(),
64 std::string(data.begin(), data.end()) )
65 );
66}
67
68void multiple_member_test()
69{
70 text_sequence data;
71 std::vector<char> temp, dest;
72
73 // Write compressed data to temp, twice in succession
74 filtering_ostream out;
75 out.push(t: lzma_compressor());
76 out.push(t: io::back_inserter(cnt&: temp));
77 io::copy(src: make_iterator_range(r&: data), snk&: out);
78 out.push(t: io::back_inserter(cnt&: temp));
79 io::copy(src: make_iterator_range(r&: data), snk&: out);
80
81 // Read compressed data from temp into dest
82 filtering_istream in;
83 in.push(t: lzma_decompressor());
84 in.push(t: array_source(&temp[0], temp.size()));
85 io::copy(src&: in, snk: io::back_inserter(cnt&: dest));
86
87 // Check that dest consists of two copies of data
88 BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size());
89 BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin()));
90 BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2));
91
92 dest.clear();
93 io::copy(
94 src: array_source(&temp[0], temp.size()),
95 snk: io::compose(filter: lzma_decompressor(), fod: io::back_inserter(cnt&: dest)));
96
97 // Check that dest consists of two copies of data
98 BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size());
99 BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin()));
100 BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2));
101}
102
103void array_source_test()
104{
105 std::string data = "simple test string.";
106 std::string encoded;
107
108 filtering_ostream out;
109 out.push(t: lzma_compressor());
110 out.push(t: io::back_inserter(cnt&: encoded));
111 io::copy(src: make_iterator_range(r&: data), snk&: out);
112
113 std::string res;
114 io::array_source src(encoded.data(),encoded.length());
115 io::copy(src: io::compose(filter: io::lzma_decompressor(), fod: src), snk: io::back_inserter(cnt&: res));
116
117 BOOST_CHECK_EQUAL(data, res);
118}
119
120void empty_file_test()
121{
122 // This test is in response to https://svn.boost.org/trac/boost/ticket/5237
123 // The previous implementation of gzip_compressor only wrote the gzip file
124 // header when the first bytes of uncompressed input were processed, causing
125 // incorrect behavior for empty files
126 BOOST_CHECK(
127 test_filter_pair( lzma_compressor(),
128 lzma_decompressor(),
129 std::string() )
130 );
131}
132
133void multipart_test()
134{
135 // This test verifies that the lzma_decompressor properly handles a file
136 // that consists of multiple concatenated files (matches unxz behaviour)
137 static const char multipart_file[] = {
138 '\xfd', '\x37', '\x7a', '\x58', '\x5a', '\x00', '\x00', '\x04', '\xe6', '\xd6', '\xb4', '\x46',
139 '\x02', '\x00', '\x21', '\x01', '\x1c', '\x00', '\x00', '\x00', '\x10', '\xcf', '\x58', '\xcc',
140 '\xe0', '\x00', '\x14', '\x00', '\x11', '\x5d', '\x00', '\x26', '\x1a', '\x49', '\xc6', '\x67',
141 '\x41', '\x3f', '\x96', '\x8c', '\x25', '\x02', '\xb3', '\x4d', '\x16', '\xa8', '\xb4', '\x40',
142 '\x00', '\x00', '\x00', '\x00', '\xeb', '\xad', '\x3f', '\xbf', '\x8c', '\x8c', '\x72', '\x25',
143 '\x00', '\x01', '\x2d', '\x15', '\x2f', '\x0b', '\x71', '\x6d', '\x1f', '\xb6', '\xf3', '\x7d',
144 '\x01', '\x00', '\x00', '\x00', '\x00', '\x04', '\x59', '\x5a', '\xfd', '\x37', '\x7a', '\x58',
145 '\x5a', '\x00', '\x00', '\x04', '\xe6', '\xd6', '\xb4', '\x46', '\x02', '\x00', '\x21', '\x01',
146 '\x1c', '\x00', '\x00', '\x00', '\x10', '\xcf', '\x58', '\xcc', '\xe0', '\x00', '\x14', '\x00',
147 '\x11', '\x5d', '\x00', '\x26', '\x1a', '\x49', '\xc6', '\x67', '\x41', '\x4d', '\x84', '\x0c',
148 '\x25', '\x1f', '\x5e', '\x1d', '\x4a', '\x91', '\x61', '\xa0', '\x00', '\x00', '\x00', '\x00',
149 '\x56', '\x76', '\x71', '\xf0', '\x54', '\x21', '\xa2', '\x5b', '\x00', '\x01', '\x2d', '\x15',
150 '\x2f', '\x0b', '\x71', '\x6d', '\x1f', '\xb6', '\xf3', '\x7d', '\x01', '\x00', '\x00', '\x00',
151 '\x00', '\x04', '\x59', '\x5a', '\xfd', '\x37', '\x7a', '\x58', '\x5a', '\x00', '\x00', '\x04',
152 '\xe6', '\xd6', '\xb4', '\x46', '\x00', '\x00', '\x00', '\x00', '\x1c', '\xdf', '\x44', '\x21',
153 '\x1f', '\xb6', '\xf3', '\x7d', '\x01', '\x00', '\x00', '\x00', '\x00', '\x04', '\x59', '\x5a',
154 '\xfd', '\x37', '\x7a', '\x58', '\x5a', '\x00', '\x00', '\x04', '\xe6', '\xd6', '\xb4', '\x46',
155 '\x02', '\x00', '\x21', '\x01', '\x1c', '\x00', '\x00', '\x00', '\x10', '\xcf', '\x58', '\xcc',
156 '\xe0', '\x00', '\x14', '\x00', '\x11', '\x5d', '\x00', '\x26', '\x1a', '\x49', '\xc6', '\x67',
157 '\x41', '\x5b', '\x71', '\x8c', '\x25', '\x3c', '\x08', '\xec', '\x79', '\xa7', '\x7b', '\x60',
158 '\x00', '\x00', '\x00', '\x00', '\xc7', '\x62', '\xbb', '\xaa', '\x59', '\x96', '\x2b', '\xa4',
159 '\x00', '\x01', '\x2d', '\x15', '\x2f', '\x0b', '\x71', '\x6d', '\x1f', '\xb6', '\xf3', '\x7d',
160 '\x01', '\x00', '\x00', '\x00', '\x00', '\x04', '\x59', '\x5a'
161 };
162
163 filtering_istream in;
164 std::string line;
165
166 in.push(t: lzma_decompressor());
167 in.push(t: io::array_source(multipart_file, sizeof(multipart_file)));
168
169 // First part
170 std::getline(is&: in, str&: line);
171 BOOST_CHECK_EQUAL("Line 1", line);
172 std::getline(is&: in, str&: line);
173 BOOST_CHECK_EQUAL("Line 2", line);
174 std::getline(is&: in, str&: line);
175 BOOST_CHECK_EQUAL("Line 3", line);
176
177 // Second part immediately follows
178 std::getline(is&: in, str&: line);
179 BOOST_CHECK_EQUAL("Line 4", line);
180 std::getline(is&: in, str&: line);
181 BOOST_CHECK_EQUAL("Line 5", line);
182 std::getline(is&: in, str&: line);
183 BOOST_CHECK_EQUAL("Line 6", line);
184
185 // Then an empty part, followed by one last 3-line part.
186 std::getline(is&: in, str&: line);
187 BOOST_CHECK_EQUAL("Line 7", line);
188 std::getline(is&: in, str&: line);
189 BOOST_CHECK_EQUAL("Line 8", line);
190 std::getline(is&: in, str&: line);
191 BOOST_CHECK_EQUAL("Line 9", line);
192
193 // Check for lzma errors too.
194 BOOST_CHECK(!in.bad());
195}
196
197void multithreaded_test()
198{
199 text_sequence data;
200
201 // Get correct compressed string at level 2.
202 // Tests legacy capability of providing a single integer to the
203 // lzma_compressor constructor to be used as the "level" to initialize
204 // lzma_params.
205 std::string correct_level_2;
206 {
207 filtering_ostream out;
208 out.push(t: lzma_compressor(2));
209 out.push(t: io::back_inserter(cnt&: correct_level_2));
210 io::copy(src: make_iterator_range(r&: data), snk&: out);
211 }
212
213 // Tests omitting the threads parameters and arriving at same compressed data.
214 BOOST_CHECK(
215 test_output_filter( lzma_compressor(lzma_params(2)),
216 std::string(data.begin(), data.end()),
217 correct_level_2 )
218 );
219
220 // Test specifying a single thread and arriving at same compressed data.
221 BOOST_CHECK(
222 test_output_filter( lzma_compressor(lzma_params(2, 1)),
223 std::string(data.begin(), data.end()),
224 correct_level_2 )
225 );
226
227 // Test specifying multiple threads and arriving at same compressed data.
228 BOOST_CHECK(
229 test_output_filter( lzma_compressor(lzma_params(2, 4)),
230 std::string(data.begin(), data.end()),
231 correct_level_2 )
232 );
233
234 // Test specifying "0" threads, which is interpreted as
235 // using all cores, or 1 thread if such capability is missing.
236 BOOST_CHECK(
237 test_output_filter( lzma_compressor(lzma_params(2, 0)),
238 std::string(data.begin(), data.end()),
239 correct_level_2 )
240 );
241
242 // Test that decompressor works to decompress the output with various thread values.
243 // Threading shouldn't affect the decompression and, in fact, isn't
244 // threaded in current implementation of liblzma. Both the level and
245 // threads options are ignored by the decompressor.
246 BOOST_CHECK(
247 test_input_filter( lzma_decompressor(lzma_params(2, 1)),
248 correct_level_2,
249 std::string(data.begin(), data.end()) )
250 );
251 BOOST_CHECK(
252 test_input_filter( lzma_decompressor(lzma_params(2, 4)),
253 correct_level_2,
254 std::string(data.begin(), data.end()) )
255 );
256 BOOST_CHECK(
257 test_input_filter( lzma_decompressor(lzma_params(2, 0)),
258 correct_level_2,
259 std::string(data.begin(), data.end()) )
260 );
261
262}
263
264test_suite* init_unit_test_suite(int, char* [])
265{
266 test_suite* test = BOOST_TEST_SUITE("lzma test");
267 test->add(BOOST_TEST_CASE(&compression_test));
268 test->add(BOOST_TEST_CASE(&multiple_member_test));
269 test->add(BOOST_TEST_CASE(&array_source_test));
270 test->add(BOOST_TEST_CASE(&empty_file_test));
271 test->add(BOOST_TEST_CASE(&multipart_test));
272 test->add(BOOST_TEST_CASE(&multithreaded_test));
273 return test;
274}
275

source code of boost/libs/iostreams/test/lzma_test.cpp