1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.compress.compressors.zstandard;
21
22 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32
33 import org.apache.commons.compress.AbstractTest;
34 import org.apache.commons.compress.compressors.CompressorInputStream;
35 import org.apache.commons.compress.compressors.CompressorOutputStream;
36 import org.apache.commons.compress.compressors.CompressorStreamFactory;
37 import org.apache.commons.io.IOUtils;
38 import org.apache.commons.io.function.IOFunction;
39 import org.apache.commons.lang3.ArrayUtils;
40 import org.junit.jupiter.api.Disabled;
41 import org.junit.jupiter.api.Test;
42 import org.junitpioneer.jupiter.cartesian.CartesianTest;
43 import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
44
45 import com.github.luben.zstd.ZstdOutputStream;
46
47
48
49
50 class ZstdRoundtripTest extends AbstractTest {
51
52 private interface OutputStreamCreator extends IOFunction<FileOutputStream, ZstdCompressorOutputStream> {
53
54 }
55
56 private void roundtrip(final OutputStreamCreator oc) throws IOException {
57 final Path input = getPath("bla.tar");
58 final File output = newTempFile(input.getFileName() + ".zstd");
59 try (FileOutputStream os = new FileOutputStream(output);
60 ZstdCompressorOutputStream zos = oc.apply(os)) {
61 zos.write(input);
62 zos.close();
63 assertTrue(zos.isClosed());
64 }
65 try (ZstdCompressorInputStream zis = new ZstdCompressorInputStream(Files.newInputStream(output.toPath()))) {
66 final byte[] expected = Files.readAllBytes(input);
67 final byte[] actual = IOUtils.toByteArray(zis);
68 assertArrayEquals(expected, actual);
69 }
70 }
71
72 @Test
73 void testDirectRoundtrip() throws Exception {
74 roundtrip(ZstdCompressorOutputStream::new);
75 }
76
77 @Test
78 void testFactoryRoundtrip() throws Exception {
79 final Path input = getPath("bla.tar");
80 final File output = newTempFile(input.getFileName() + ".zstd");
81 try (OutputStream os = Files.newOutputStream(output.toPath());
82 CompressorOutputStream<?> zos = new CompressorStreamFactory().createCompressorOutputStream("zstd", os)) {
83 zos.write(input);
84 }
85 try (InputStream inputStream = Files.newInputStream(output.toPath());
86 CompressorInputStream zis = new CompressorStreamFactory().createCompressorInputStream("zstd", inputStream)) {
87 final byte[] expected = Files.readAllBytes(input);
88 final byte[] actual = IOUtils.toByteArray(zis);
89 assertArrayEquals(expected, actual);
90 }
91 }
92
93 @Test
94 void testRoundtripSetChainLogNonDefaultMax() throws Exception {
95 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setChainLog(ZstdConstants.ZSTD_CHAINLOG_MAX).get());
96 }
97
98 @Test
99 void testRoundtripSetChainLogNonDefaultMin() throws Exception {
100 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setChainLog(ZstdConstants.ZSTD_CHAINLOG_MIN).get());
101 }
102
103 @Test
104 void testRoundtripSetChecksumNonDefault() throws Exception {
105 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setChecksum(true).get());
106 }
107
108 @Test
109 void testRoundtripSetCloseFrameOnFlushNonDefault() throws Exception {
110 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setCloseFrameOnFlush(true).get());
111 }
112
113 @Test
114 void testRoundtripSetHashLogNonDefaultMax() throws Exception {
115 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setHashLog(ZstdConstants.ZSTD_HASHLOG_MAX).get());
116 }
117
118 @Test
119 void testRoundtripSetHashLogNonDefaultMin() throws Exception {
120 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setHashLog(ZstdConstants.ZSTD_HASHLOG_MIN).get());
121 }
122
123 @Test
124 void testRoundtripSetJobSizeNonDefault() throws Exception {
125 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setJobSize(1).get());
126 }
127
128 @Test
129 void testRoundtripSetLevelNonDefault() throws Exception {
130 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setLevel(1).get());
131 }
132
133 @Test
134 void testRoundtripSetMinMatchNonDefaultMax() throws Exception {
135 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setMinMatch(ZstdConstants.ZSTD_MINMATCH_MAX).get());
136 }
137
138 @Test
139 void testRoundtripSetMinMatchNonDefaultMin() throws Exception {
140 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setMinMatch(ZstdConstants.ZSTD_MINMATCH_MIN).get());
141 }
142
143 @Test
144 void testRoundtripSetOverlapLogNonDefault() throws Exception {
145 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setOverlapLog(1).get());
146 }
147
148 @Test
149 void testRoundtripSetSearchLogNonDefault() throws Exception {
150 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setSearchLog(1).get());
151 }
152
153 @Test
154 void testRoundtripSetStrategyNonDefault() throws Exception {
155 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setStrategy(1).get());
156 }
157
158 @Test
159 @Disabled("com.github.luben.zstd.ZstdIOException: Frame requires too much memory for decoding")
160 void testRoundtripSetWindowLogNonDefaultMax() throws Exception {
161 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setWindowLog(ZstdConstants.ZSTD_WINDOWLOG_MAX).get());
162 }
163
164 @Test
165 void testRoundtripSetWindowLogNonDefaultMin() throws Exception {
166 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setWindowLog(ZstdConstants.ZSTD_WINDOWLOG_MIN).get());
167 }
168
169 @Test
170 void testRoundtripSetWorkersNonDefault() throws Exception {
171 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setWorkers(1).get());
172 }
173
174 @Test
175 void testRoundtripSetZstdDict() throws Exception {
176
177
178 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setDict(null).get());
179 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setDict(ArrayUtils.EMPTY_BYTE_ARRAY).get());
180 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setDict(new byte[512]).get());
181 }
182
183 @CartesianTest
184
185 void testRoundtripWithAll(
186 @Values(ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) final int level,
187 @Values(booleans = { false, true }) final boolean checksum,
188 @Values(booleans = { false, true }) final boolean closeFrameOnFlush,
189 @Values(ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) final int strategy,
190 @Values(ints = { 0, 6, 9 }) final int overlapLog
191 ) throws Exception {
192 roundtrip(os -> ZstdCompressorOutputStream.builder()
193 .setChainLog(0)
194 .setChecksum(checksum)
195 .setCloseFrameOnFlush(closeFrameOnFlush)
196 .setDict(null)
197 .setHashLog(0)
198 .setJobSize(0)
199 .setLevel(level)
200 .setMinMatch(0)
201 .setOutputStream(os)
202 .setOverlapLog(overlapLog)
203 .setSearchLog(0)
204 .setStrategy(strategy)
205 .setWindowLog(0)
206 .setWorkers(0)
207 .get());
208 }
209
210
211 @Test
212 void testRoundtripWithChecksum() throws Exception {
213 roundtrip(os -> new ZstdCompressorOutputStream(os, 3, false, true));
214 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setLevel(3).setCloseFrameOnFlush(true).setChecksum(true).get());
215 }
216
217 @Test
218 void testRoundtripWithCloseFrameOnFlush() throws Exception {
219 roundtrip(os -> new ZstdCompressorOutputStream(os, 3, true));
220 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setLevel(3).setCloseFrameOnFlush(true).get());
221 }
222
223 @Test
224 void testRoundtripWithCustomLevel() throws Exception {
225 roundtrip(os -> new ZstdCompressorOutputStream(os, 1));
226 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(os).setLevel(1).get());
227 }
228
229 @Test
230 void testRoundtripWithZstdOutputStream() throws Exception {
231 roundtrip(os -> ZstdCompressorOutputStream.builder().setOutputStream(new ZstdOutputStream(os)).get());
232 roundtrip(os -> new ZstdCompressorOutputStream(new ZstdOutputStream(os)));
233 }
234 }