View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.compressors;
20  
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.nio.file.Files;
32  import java.time.Instant;
33  import java.util.zip.Deflater;
34  import java.util.zip.GZIPInputStream;
35  
36  import org.apache.commons.compress.AbstractTest;
37  import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
38  import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
39  import org.apache.commons.compress.compressors.gzip.GzipParameters;
40  import org.apache.commons.io.IOUtils;
41  import org.junit.jupiter.api.Test;
42  import org.junit.jupiter.params.ParameterizedTest;
43  import org.junit.jupiter.params.provider.ValueSource;
44  
45  public final class GZipTest extends AbstractTest {
46  
47      private static final int MTIME = 123456000;
48      private static final Instant MTIME_INSTANT = Instant.ofEpochSecond(MTIME);
49  
50      @Test
51      void testConcatenatedStreamsReadFirstOnly() throws Exception {
52          final File input = getFile("multiple.gz");
53          try (InputStream is = Files.newInputStream(input.toPath())) {
54              try (CompressorInputStream in = new CompressorStreamFactory().createCompressorInputStream("gz", is)) {
55                  assertEquals('a', in.read());
56                  assertEquals(-1, in.read());
57              }
58          }
59      }
60  
61      @Test
62      void testConcatenatedStreamsReadFully() throws Exception {
63          final File input = getFile("multiple.gz");
64          try (InputStream is = Files.newInputStream(input.toPath())) {
65              try (CompressorInputStream in = new GzipCompressorInputStream(is, true)) {
66                  assertEquals('a', in.read());
67                  assertEquals('b', in.read());
68                  assertEquals(0, in.available());
69                  assertEquals(-1, in.read());
70              }
71          }
72      }
73  
74      /**
75       * @see "https://issues.apache.org/jira/browse/COMPRESS-84"
76       */
77      @Test
78      void testCorruptedInput() throws Exception {
79          final byte[] data = readAllBytes("bla.tgz");
80          try (InputStream in = new ByteArrayInputStream(data, 0, data.length - 1);
81                  CompressorInputStream cin = new CompressorStreamFactory().createCompressorInputStream("gz", in);
82                  OutputStream out = new ByteArrayOutputStream()) {
83              assertThrows(IOException.class, () -> IOUtils.copy(cin, out), "Expected an exception");
84          }
85      }
86  
87      private void testExtraFlags(final int compressionLevel, final int flag, final int bufferSize) throws Exception {
88          final byte[] content = readAllBytes("test3.xml");
89  
90          final ByteArrayOutputStream bout = new ByteArrayOutputStream();
91  
92          final GzipParameters parameters = new GzipParameters();
93          parameters.setCompressionLevel(compressionLevel);
94          parameters.setBufferSize(bufferSize);
95          try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(bout, parameters)) {
96              IOUtils.copy(new ByteArrayInputStream(content), out);
97              out.flush();
98          }
99  
100         assertEquals(flag, bout.toByteArray()[8], "extra flags (XFL)");
101     }
102 
103     @Test
104     void testExtraFlagsBestCompression() throws Exception {
105         testExtraFlags(Deflater.BEST_COMPRESSION, 2, 1024);
106     }
107 
108     @Test
109     void testExtraFlagsDefaultCompression() throws Exception {
110         testExtraFlags(Deflater.DEFAULT_COMPRESSION, 0, 4096);
111     }
112 
113     @Test
114     void testExtraFlagsFastestCompression() throws Exception {
115         testExtraFlags(Deflater.BEST_SPEED, 4, 128);
116     }
117 
118     @Test
119     void testGzipCreation() throws Exception {
120         final File input = getFile("test1.xml");
121         final File output = newTempFile("test1.xml.gz");
122         try (OutputStream out = Files.newOutputStream(output.toPath())) {
123             try (CompressorOutputStream<?> cos = new CompressorStreamFactory().createCompressorOutputStream("gz", out)) {
124                 cos.write(input);
125             }
126         }
127     }
128 
129     @Test
130     void testGzipUnarchive() throws Exception {
131         final File input = getFile("bla.tgz");
132         final File output = newTempFile("bla.tar");
133         try (InputStream is = Files.newInputStream(input.toPath())) {
134             try (CompressorInputStream in = new CompressorStreamFactory().createCompressorInputStream("gz", is);) {
135                 Files.copy(in, output.toPath());
136             }
137         }
138     }
139 
140     @Test
141     void testInteroperabilityWithGzipCompressorInputStream() throws Exception {
142         final byte[] content = readAllBytes("test3.xml");
143         final ByteArrayOutputStream bout = new ByteArrayOutputStream();
144         final GzipParameters parameters = new GzipParameters();
145         parameters.setCompressionLevel(Deflater.BEST_COMPRESSION);
146         parameters.setOperatingSystem(3);
147         parameters.setFilename("test3.xml");
148         assertEquals(parameters.getFilename(), parameters.getFileName());
149         parameters.setFileName("test3.xml");
150         assertEquals(parameters.getFilename(), parameters.getFileName());
151         parameters.setComment("Test file");
152         parameters.setModificationTime(System.currentTimeMillis());
153         try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(bout, parameters)) {
154             out.write(content);
155             out.flush();
156         }
157         try (GzipCompressorInputStream in = new GzipCompressorInputStream(new ByteArrayInputStream(bout.toByteArray()))) {
158             final byte[] content2 = IOUtils.toByteArray(in);
159             assertArrayEquals(content, content2, "uncompressed content");
160         }
161     }
162 
163     @Test
164     void testInteroperabilityWithGZIPInputStream() throws Exception {
165         final byte[] content = readAllBytes("test3.xml");
166         final ByteArrayOutputStream bout = new ByteArrayOutputStream();
167         final GzipParameters parameters = new GzipParameters();
168         parameters.setCompressionLevel(Deflater.BEST_COMPRESSION);
169         parameters.setOperatingSystem(3);
170         parameters.setFilename("test3.xml");
171         assertEquals(parameters.getFilename(), parameters.getFileName());
172         parameters.setFileName("test3.xml");
173         assertEquals(parameters.getFilename(), parameters.getFileName());
174         parameters.setComment("Test file");
175         parameters.setModificationTime(System.currentTimeMillis());
176         try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(bout, parameters)) {
177             out.write(content);
178             out.flush();
179         }
180         final GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(bout.toByteArray()));
181         final byte[] content2 = IOUtils.toByteArray(in);
182         assertArrayEquals(content, content2, "uncompressed content");
183     }
184 
185     @ParameterizedTest
186     @ValueSource(ints = { 0, -1 })
187     void testInvalidBufferSize(final int bufferSize) {
188         final GzipParameters parameters = new GzipParameters();
189         assertThrows(IllegalArgumentException.class, () -> parameters.setBufferSize(bufferSize), "IllegalArgumentException not thrown");
190     }
191 
192     @ParameterizedTest
193     @ValueSource(ints = { 10, -5 })
194     void testInvalidCompressionLevel(final int compressionLevel) {
195         final GzipParameters parameters = new GzipParameters();
196         assertThrows(IllegalArgumentException.class, () -> parameters.setCompressionLevel(compressionLevel), "IllegalArgumentException not thrown");
197     }
198 
199     @Test
200     void testMetadataRoundTrip() throws Exception {
201         final ByteArrayOutputStream bout = new ByteArrayOutputStream();
202 
203         final GzipParameters parameters = new GzipParameters();
204         parameters.setCompressionLevel(Deflater.BEST_COMPRESSION);
205         assertEquals(0, parameters.getModificationTime());
206         parameters.setModificationInstant(null);
207         assertEquals(0, parameters.getModificationTime());
208         parameters.setModificationInstant(MTIME_INSTANT);
209         assertEquals(MTIME_INSTANT.getEpochSecond(), parameters.getModificationTime());
210         assertEquals(MTIME_INSTANT, parameters.getModificationInstant());
211         parameters.setOS(GzipParameters.OS.Z_SYSTEM);
212         assertEquals(GzipParameters.OS.Z_SYSTEM, parameters.getOS());
213         parameters.setOS(null);
214         assertEquals(GzipParameters.OS.UNKNOWN, parameters.getOS());
215         parameters.setOperatingSystem(13);
216         assertEquals(GzipParameters.OS.ACORN_RISCOS, parameters.getOS());
217         parameters.setFilename("test3.xml");
218         assertEquals(parameters.getFilename(), parameters.getFileName());
219         parameters.setFileName("test3.xml");
220         assertEquals(parameters.getFilename(), parameters.getFileName());
221         parameters.setComment("Umlaute möglich?");
222         try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(bout, parameters)) {
223             out.write(getFile("test3.xml"));
224         }
225 
226         final GzipCompressorInputStream input = new GzipCompressorInputStream(new ByteArrayInputStream(bout.toByteArray()));
227         input.close();
228         final GzipParameters readParams = input.getMetaData();
229         assertEquals(Deflater.BEST_COMPRESSION, readParams.getCompressionLevel());
230         assertEquals(123456000, readParams.getModificationTime());
231         assertEquals(13, readParams.getOperatingSystem());
232         assertEquals(GzipParameters.OS.ACORN_RISCOS, readParams.getOS());
233         assertEquals("test3.xml", readParams.getFileName());
234         assertEquals("test3.xml", readParams.getFilename());
235         assertEquals("Umlaute möglich?", readParams.getComment());
236     }
237 
238     @Test
239     void testMultiByteReadConsistentlyReturnsMinusOneAtEof() throws IOException {
240         final File input = getFile("bla.tgz");
241         final byte[] buf = new byte[2];
242         try (InputStream is = Files.newInputStream(input.toPath());
243                 GzipCompressorInputStream in = new GzipCompressorInputStream(is)) {
244             IOUtils.toByteArray(in);
245             assertEquals(-1, in.read(buf));
246             assertEquals(-1, in.read(buf));
247         }
248     }
249 
250     @Test
251     void testOverWrite() throws Exception {
252         final GzipCompressorOutputStream out = new GzipCompressorOutputStream(new ByteArrayOutputStream());
253         out.close();
254         assertThrows(IOException.class, () -> out.write(0));
255     }
256 
257     @Test
258     void testSingleByteReadConsistentlyReturnsMinusOneAtEof() throws IOException {
259         final File input = getFile("bla.tgz");
260         try (InputStream is = Files.newInputStream(input.toPath());
261                 GzipCompressorInputStream in = new GzipCompressorInputStream(is)) {
262             IOUtils.toByteArray(in);
263             assertEquals(-1, in.read());
264             assertEquals(-1, in.read());
265         }
266     }
267 }