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