• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // (C) COPYRIGHT 2018 Reimar Döffinger
2 // Based on zstd_test.cpp by:
3 // (C) COPYRIGHT 2017 ARM Limited
4 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
5 // (C) Copyright 2004-2007 Jonathan Turkanis
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
8 
9 // See http://www.boost.org/libs/iostreams for documentation.
10 
11 // Note: basically a copy-paste of the gzip test
12 
13 #include <cstddef>
14 #include <string>
15 #include <boost/iostreams/copy.hpp>
16 #include <boost/iostreams/device/array.hpp>
17 #include <boost/iostreams/device/back_inserter.hpp>
18 #include <boost/iostreams/filter/zstd.hpp>
19 #include <boost/iostreams/filter/test.hpp>
20 #include <boost/iostreams/filtering_stream.hpp>
21 #include <boost/ref.hpp>
22 #include <boost/range/iterator_range.hpp>
23 #include <boost/test/test_tools.hpp>
24 #include <boost/test/unit_test.hpp>
25 #include "detail/sequence.hpp"
26 #include "detail/verification.hpp"
27 
28 using namespace boost;
29 using namespace boost::iostreams;
30 using namespace boost::iostreams::test;
31 namespace io = boost::iostreams;
32 using boost::unit_test::test_suite;
33 
34 struct zstd_alloc : std::allocator<char> {
zstd_alloczstd_alloc35     zstd_alloc() { }
zstd_alloczstd_alloc36     zstd_alloc(const zstd_alloc& other) { }
37     template<typename T>
zstd_alloczstd_alloc38     zstd_alloc(const std::allocator<T>& other) { }
39 };
40 
compression_test()41 void compression_test()
42 {
43     text_sequence      data;
44 
45     // Test compression and decompression with custom allocator
46     BOOST_CHECK(
47         test_filter_pair( basic_zstd_compressor<zstd_alloc>(),
48                           basic_zstd_decompressor<zstd_alloc>(),
49                           std::string(data.begin(), data.end()) )
50     );
51 }
52 
multiple_member_test()53 void multiple_member_test()
54 {
55     text_sequence      data;
56     std::vector<char>  temp, dest;
57 
58     // Write compressed data to temp, twice in succession
59     filtering_ostream out;
60     out.push(zstd_compressor());
61     out.push(io::back_inserter(temp));
62     io::copy(make_iterator_range(data), out);
63     out.push(io::back_inserter(temp));
64     io::copy(make_iterator_range(data), out);
65     BOOST_CHECK(std::equal(temp.begin(), temp.begin() + temp.size()/2, temp.begin() + temp.size()/2));
66 
67     // Read compressed data from temp into dest
68     filtering_istream in;
69     in.push(zstd_decompressor());
70     in.push(array_source(&temp[0], temp.size()));
71     io::copy(in, io::back_inserter(dest));
72 
73     // Check that dest consists of two copies of data
74     BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size());
75     BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin()));
76     BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2));
77 
78     dest.clear();
79     io::copy(
80         array_source(&temp[0], temp.size()),
81         io::compose(zstd_decompressor(), io::back_inserter(dest)));
82 
83     // Check that dest consists of two copies of data
84     BOOST_REQUIRE_EQUAL(data.size() * 2, dest.size());
85     BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin()));
86     BOOST_CHECK(std::equal(data.begin(), data.end(), dest.begin() + dest.size() / 2));
87 }
88 
array_source_test()89 void array_source_test()
90 {
91     std::string data = "simple test string.";
92     std::string encoded;
93 
94     filtering_ostream out;
95     out.push(zstd_compressor());
96     out.push(io::back_inserter(encoded));
97     io::copy(make_iterator_range(data), out);
98 
99     std::string res;
100     io::array_source src(encoded.data(),encoded.length());
101     io::copy(io::compose(io::zstd_decompressor(), src), io::back_inserter(res));
102 
103     BOOST_CHECK_EQUAL(data, res);
104 }
105 
empty_file_test()106 void empty_file_test()
107 {
108     // This test is in response to https://svn.boost.org/trac/boost/ticket/5237
109     // The previous implementation of gzip_compressor only wrote the gzip file
110     // header when the first bytes of uncompressed input were processed, causing
111     // incorrect behavior for empty files
112     BOOST_CHECK(
113         test_filter_pair( zstd_compressor(),
114                           zstd_decompressor(),
115                           std::string() )
116     );
117 }
118 
multipart_test()119 void multipart_test()
120 {
121     // This test verifies that the zstd_decompressor properly handles a file
122     // that consists of multiple concatenated files (matches unzstd behaviour)
123     static const char multipart_file[] = {
124         '\x28', '\xb5', '\x2f', '\xfd', '\x24', '\x15', '\x95', '\x00', '\x00', '\x50', '\x4c', '\x69',
125         '\x6e', '\x65', '\x20', '\x31', '\x0a', '\x32', '\x33', '\x0a', '\x02', '\x00', '\x60', '\x84',
126         '\xae', '\x62', '\x04', '\x19', '\xf8', '\xe1', '\x2d', '\x28', '\xb5', '\x2f', '\xfd', '\x24',
127         '\x15', '\x95', '\x00', '\x00', '\x50', '\x4c', '\x69', '\x6e', '\x65', '\x20', '\x34', '\x0a',
128         '\x35', '\x36', '\x0a', '\x02', '\x00', '\x60', '\x84', '\xae', '\x62', '\x04', '\x5f', '\xcf',
129         '\xd5', '\xb8', '\x28', '\xb5', '\x2f', '\xfd', '\x24', '\x00', '\x01', '\x00', '\x00', '\x99',
130         '\xe9', '\xd8', '\x51', '\x28', '\xb5', '\x2f', '\xfd', '\x24', '\x15', '\x95', '\x00', '\x00',
131         '\x50', '\x4c', '\x69', '\x6e', '\x65', '\x20', '\x37', '\x0a', '\x38', '\x39', '\x0a', '\x02',
132         '\x00', '\x60', '\x84', '\xae', '\x62', '\x04', '\x94', '\x13', '\xdb', '\xae'
133     };
134 
135     filtering_istream in;
136     std::string line;
137 
138     in.push(zstd_decompressor());
139     in.push(io::array_source(multipart_file, sizeof(multipart_file)));
140 
141     // First part
142     std::getline(in, line);
143     BOOST_CHECK_EQUAL("Line 1", line);
144     std::getline(in, line);
145     BOOST_CHECK_EQUAL("Line 2", line);
146     std::getline(in, line);
147     BOOST_CHECK_EQUAL("Line 3", line);
148 
149     // Second part immediately follows
150     std::getline(in, line);
151     BOOST_CHECK_EQUAL("Line 4", line);
152     std::getline(in, line);
153     BOOST_CHECK_EQUAL("Line 5", line);
154     std::getline(in, line);
155     BOOST_CHECK_EQUAL("Line 6", line);
156 
157     // Then an empty part, followed by one last 3-line part.
158     std::getline(in, line);
159     BOOST_CHECK_EQUAL("Line 7", line);
160     std::getline(in, line);
161     BOOST_CHECK_EQUAL("Line 8", line);
162     std::getline(in, line);
163     BOOST_CHECK_EQUAL("Line 9", line);
164 
165     // Check for zstd errors too.
166     BOOST_CHECK(!in.bad());
167 }
168 
init_unit_test_suite(int,char * [])169 test_suite* init_unit_test_suite(int, char* [])
170 {
171     test_suite* test = BOOST_TEST_SUITE("zstd test");
172     test->add(BOOST_TEST_CASE(&compression_test));
173     test->add(BOOST_TEST_CASE(&multiple_member_test));
174     test->add(BOOST_TEST_CASE(&array_source_test));
175     test->add(BOOST_TEST_CASE(&empty_file_test));
176     test->add(BOOST_TEST_CASE(&multipart_test));
177     return test;
178 }
179