]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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 | ||
27 | using namespace boost; | |
28 | using namespace boost::iostreams; | |
29 | using namespace boost::iostreams::test; | |
30 | namespace io = boost::iostreams; | |
31 | using boost::unit_test::test_suite; | |
32 | ||
1e59de90 TL |
33 | template<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 | }; | |
b32b8144 FG |
52 | }; |
53 | ||
1e59de90 TL |
54 | typedef basic_test_alloc<char> lzma_alloc; |
55 | ||
b32b8144 FG |
56 | void 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 | ||
68 | void 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(lzma_compressor()); | |
76 | out.push(io::back_inserter(temp)); | |
77 | io::copy(make_iterator_range(data), out); | |
78 | out.push(io::back_inserter(temp)); | |
79 | io::copy(make_iterator_range(data), out); | |
80 | ||
81 | // Read compressed data from temp into dest | |
82 | filtering_istream in; | |
83 | in.push(lzma_decompressor()); | |
84 | in.push(array_source(&temp[0], temp.size())); | |
85 | io::copy(in, io::back_inserter(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 | array_source(&temp[0], temp.size()), | |
95 | io::compose(lzma_decompressor(), io::back_inserter(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 | ||
103 | void array_source_test() | |
104 | { | |
105 | std::string data = "simple test string."; | |
106 | std::string encoded; | |
107 | ||
108 | filtering_ostream out; | |
109 | out.push(lzma_compressor()); | |
110 | out.push(io::back_inserter(encoded)); | |
111 | io::copy(make_iterator_range(data), out); | |
112 | ||
113 | std::string res; | |
114 | io::array_source src(encoded.data(),encoded.length()); | |
115 | io::copy(io::compose(io::lzma_decompressor(), src), io::back_inserter(res)); | |
116 | ||
117 | BOOST_CHECK_EQUAL(data, res); | |
118 | } | |
119 | ||
120 | void 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 | ||
133 | void 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(lzma_decompressor()); | |
167 | in.push(io::array_source(multipart_file, sizeof(multipart_file))); | |
168 | ||
169 | // First part | |
170 | std::getline(in, line); | |
171 | BOOST_CHECK_EQUAL("Line 1", line); | |
172 | std::getline(in, line); | |
173 | BOOST_CHECK_EQUAL("Line 2", line); | |
174 | std::getline(in, line); | |
175 | BOOST_CHECK_EQUAL("Line 3", line); | |
176 | ||
177 | // Second part immediately follows | |
178 | std::getline(in, line); | |
179 | BOOST_CHECK_EQUAL("Line 4", line); | |
180 | std::getline(in, line); | |
181 | BOOST_CHECK_EQUAL("Line 5", line); | |
182 | std::getline(in, line); | |
183 | BOOST_CHECK_EQUAL("Line 6", line); | |
184 | ||
185 | // Then an empty part, followed by one last 3-line part. | |
186 | std::getline(in, line); | |
187 | BOOST_CHECK_EQUAL("Line 7", line); | |
188 | std::getline(in, line); | |
189 | BOOST_CHECK_EQUAL("Line 8", line); | |
190 | std::getline(in, line); | |
191 | BOOST_CHECK_EQUAL("Line 9", line); | |
192 | ||
193 | // Check for lzma errors too. | |
194 | BOOST_CHECK(!in.bad()); | |
195 | } | |
196 | ||
92f5a8d4 TL |
197 | void 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(lzma_compressor(2)); | |
209 | out.push(io::back_inserter(correct_level_2)); | |
210 | io::copy(make_iterator_range(data), 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 | ||
b32b8144 FG |
264 | test_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)); | |
92f5a8d4 | 272 | test->add(BOOST_TEST_CASE(&multithreaded_test)); |
b32b8144 FG |
273 | return test; |
274 | } |