lzma_test.cpp 10 KB

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