• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * http://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.apache.commons.compress.AbstractTestCase.getFile;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27 
28 import java.io.BufferedInputStream;
29 import java.io.ByteArrayInputStream;
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 
34 import org.apache.commons.compress.MemoryLimitException;
35 import org.apache.commons.compress.MockEvilInputStream;
36 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
37 import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
38 import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
39 import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream;
40 import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
41 import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
42 import org.junit.Test;
43 
44 @SuppressWarnings("deprecation") // deliberately tests setDecompressConcatenated
45 public final class DetectCompressorTestCase {
46 
47     final CompressorStreamFactory factory = new CompressorStreamFactory();
48     private static final CompressorStreamFactory factoryTrue = new CompressorStreamFactory(true);
49     private static final CompressorStreamFactory factoryFalse = new CompressorStreamFactory(false);
50 
51     // Must be static to allow use in the TestData entries
52     private static final CompressorStreamFactory factorySetTrue;
53     private static final CompressorStreamFactory factorySetFalse;
54 
55     static {
56         factorySetTrue = new CompressorStreamFactory();
57         factorySetTrue.setDecompressConcatenated(true);
58         factorySetFalse = new CompressorStreamFactory();
59         factorySetFalse.setDecompressConcatenated(false);
60     }
61 
62     static class TestData {
63         final String fileName; // The multiple file name
64         final char[] entryNames; // expected entries ...
65         final CompressorStreamFactory factory; // ... when using this factory
66         final boolean concat; // expected value for decompressConcatenated
TestData(final String name, final char[] names, final CompressorStreamFactory factory, final boolean concat)67         TestData(final String name, final char[] names, final CompressorStreamFactory factory, final boolean concat) {
68             this.fileName = name;
69             this.entryNames = names;
70             this.factory = factory;
71             this.concat = concat;
72         }
73     }
74 
75     private final TestData[] tests = {
76         new TestData("multiple.bz2", new char[]{'a','b'}, factoryTrue, true),
77         new TestData("multiple.bz2", new char[]{'a','b'}, factorySetTrue, true),
78         new TestData("multiple.bz2", new char[]{'a'}, factoryFalse, false),
79         new TestData("multiple.bz2", new char[]{'a'}, factorySetFalse, false),
80         new TestData("multiple.bz2", new char[]{'a'}, factory, false),
81 
82         new TestData("multiple.gz", new char[]{'a','b'}, factoryTrue, true),
83         new TestData("multiple.gz", new char[]{'a','b'}, factorySetTrue, true),
84         new TestData("multiple.gz", new char[]{'a'}, factoryFalse, false),
85         new TestData("multiple.gz", new char[]{'a'}, factorySetFalse, false),
86         new TestData("multiple.gz", new char[]{'a'}, factory, false),
87 
88         new TestData("multiple.xz", new char[]{'a','b'}, factoryTrue, true),
89         new TestData("multiple.xz", new char[]{'a','b'}, factorySetTrue, true),
90         new TestData("multiple.xz", new char[]{'a'}, factoryFalse, false),
91         new TestData("multiple.xz", new char[]{'a'}, factorySetFalse, false),
92         new TestData("multiple.xz", new char[]{'a'}, factory, false),
93     };
94 
95     @Test
testDetection()96     public void testDetection() throws Exception {
97         final CompressorInputStream bzip2 = getStreamFor("bla.txt.bz2");
98         assertNotNull(bzip2);
99         assertTrue(bzip2 instanceof BZip2CompressorInputStream);
100 
101         final CompressorInputStream gzip = getStreamFor("bla.tgz");
102         assertNotNull(gzip);
103         assertTrue(gzip instanceof GzipCompressorInputStream);
104 
105         final CompressorInputStream pack200 = getStreamFor("bla.pack");
106         assertNotNull(pack200);
107         assertTrue(pack200 instanceof Pack200CompressorInputStream);
108 
109         final CompressorInputStream xz = getStreamFor("bla.tar.xz");
110         assertNotNull(xz);
111         assertTrue(xz instanceof XZCompressorInputStream);
112 
113         final CompressorInputStream zlib = getStreamFor("bla.tar.deflatez");
114         assertNotNull(zlib);
115         assertTrue(zlib instanceof DeflateCompressorInputStream);
116 
117         final CompressorInputStream zstd = getStreamFor("bla.tar.zst");
118         assertNotNull(zstd);
119         assertTrue(zstd instanceof ZstdCompressorInputStream);
120 
121         try {
122             factory.createCompressorInputStream(new ByteArrayInputStream(new byte[0]));
123             fail("No exception thrown for an empty input stream");
124         } catch (final CompressorException e) {
125             // expected
126         }
127     }
128 
129     @Test
testDetect()130     public void testDetect() throws Exception {
131 
132         assertEquals(CompressorStreamFactory.BZIP2, detect("bla.txt.bz2"));
133         assertEquals(CompressorStreamFactory.GZIP, detect("bla.tgz"));
134         assertEquals(CompressorStreamFactory.PACK200, detect("bla.pack"));
135         assertEquals(CompressorStreamFactory.XZ, detect("bla.tar.xz"));
136         assertEquals(CompressorStreamFactory.DEFLATE, detect("bla.tar.deflatez"));
137         assertEquals(CompressorStreamFactory.LZ4_FRAMED, detect("bla.tar.lz4"));
138         assertEquals(CompressorStreamFactory.LZMA, detect("bla.tar.lzma"));
139         assertEquals(CompressorStreamFactory.SNAPPY_FRAMED, detect("bla.tar.sz"));
140         assertEquals(CompressorStreamFactory.Z, detect("bla.tar.Z"));
141         assertEquals(CompressorStreamFactory.ZSTANDARD, detect("bla.tar.zst"));
142 
143         //make sure we don't oom on detect
144         assertEquals(CompressorStreamFactory.Z, detect("COMPRESS-386"));
145         assertEquals(CompressorStreamFactory.LZMA, detect("COMPRESS-382"));
146 
147         try {
148             CompressorStreamFactory.detect(new BufferedInputStream(new ByteArrayInputStream(new byte[0])));
149             fail("shouldn't be able to detect empty stream");
150         } catch (CompressorException e) {
151             assertEquals("No Compressor found for the stream signature.", e.getMessage());
152         }
153 
154         try {
155             CompressorStreamFactory.detect(null);
156             fail("shouldn't be able to detect null stream");
157         } catch (IllegalArgumentException e) {
158             assertEquals("Stream must not be null.", e.getMessage());
159         }
160 
161         try {
162             CompressorStreamFactory.detect(new BufferedInputStream(new MockEvilInputStream()));
163             fail("Expected IOException");
164         } catch (CompressorException e) {
165             assertEquals("IOException while reading signature.", e.getMessage());
166         }
167 
168 
169     }
170 
detect(String testFileName)171     private String detect(String testFileName) throws IOException, CompressorException {
172         String name = null;
173         try (InputStream is = new BufferedInputStream(
174                 new FileInputStream(getFile(testFileName)))) {
175             name = CompressorStreamFactory.detect(is);
176         }
177         return name;
178     }
179 
180     @Test(expected = MemoryLimitException.class)
testLZMAMemoryLimit()181     public void testLZMAMemoryLimit() throws Exception {
182         getStreamFor("COMPRESS-382", 100);
183     }
184 
185     @Test(expected = MemoryLimitException.class)
testZMemoryLimit()186     public void testZMemoryLimit() throws Exception {
187         getStreamFor("COMPRESS-386", 100);
188     }
189 
190     @Test(expected = MemoryLimitException.class)
testXZMemoryLimitOnRead()191     public void testXZMemoryLimitOnRead() throws Exception {
192         //Even though the file is very small, the memory limit
193         //has to be quite large (8296 KiB) because of the dictionary size
194 
195         //This is triggered on read(); not during initialization.
196         //This test is here instead of the xz unit test to make sure
197         //that the parameter is properly passed via the CompressorStreamFactory
198         try (InputStream compressorIs = getStreamFor("bla.tar.xz", 100)) {
199             compressorIs.read();
200         }
201     }
202 
203     @Test(expected = MemoryLimitException.class)
testXZMemoryLimitOnSkip()204     public void testXZMemoryLimitOnSkip() throws Exception {
205         try (InputStream compressorIs = getStreamFor("bla.tar.xz", 100)) {
206             compressorIs.skip(10);
207         }
208     }
209 
getStreamFor(final String fileName, final int memoryLimitInKb)210     private InputStream getStreamFor(final String fileName, final int memoryLimitInKb) throws Exception {
211         CompressorStreamFactory fac = new CompressorStreamFactory(true,
212                 memoryLimitInKb);
213         InputStream is = new BufferedInputStream(
214                 new FileInputStream(getFile(fileName)));
215         try {
216             return fac.createCompressorInputStream(is);
217         } catch (CompressorException e) {
218             if (e.getCause() != null && e.getCause() instanceof Exception) {
219                 //unwrap cause to reveal MemoryLimitException
220                 throw (Exception)e.getCause();
221             } else {
222                 throw e;
223             }
224         }
225 
226     }
227 
228 
229     @Test
testOverride()230     public void testOverride() {
231         CompressorStreamFactory fac = new CompressorStreamFactory();
232         assertFalse(fac.getDecompressConcatenated());
233         fac.setDecompressConcatenated(true);
234         assertTrue(fac.getDecompressConcatenated());
235 
236         fac = new CompressorStreamFactory(false);
237         assertFalse(fac.getDecompressConcatenated());
238         try {
239             fac.setDecompressConcatenated(true);
240             fail("Expected IllegalStateException");
241         } catch (final IllegalStateException ise) {
242             // expected
243         }
244 
245         fac = new CompressorStreamFactory(true);
246         assertTrue(fac.getDecompressConcatenated());
247         try {
248             fac.setDecompressConcatenated(true);
249             fail("Expected IllegalStateException");
250         } catch (final IllegalStateException ise) {
251             // expected
252         }
253     }
254 
255     @Test
testMutiples()256     public void testMutiples() throws Exception {
257         for(int i=0; i <tests.length; i++) {
258             final TestData test = tests[i];
259             final CompressorStreamFactory fac = test.factory;
260             assertNotNull("Test entry "+i, fac);
261             assertEquals("Test entry "+i, test.concat, fac.getDecompressConcatenated());
262             final CompressorInputStream in = getStreamFor(test.fileName, fac);
263             assertNotNull("Test entry "+i,in);
264             for (final char entry : test.entryNames) {
265                 assertEquals("Test entry" + i, entry, in.read());
266             }
267             assertEquals(0, in.available());
268             assertEquals(-1, in.read());
269         }
270     }
271 
getStreamFor(final String resource)272     private CompressorInputStream getStreamFor(final String resource)
273             throws CompressorException, IOException {
274         return factory.createCompressorInputStream(
275                    new BufferedInputStream(new FileInputStream(
276                        getFile(resource))));
277     }
278 
getStreamFor(final String resource, final CompressorStreamFactory factory)279     private CompressorInputStream getStreamFor(final String resource, final CompressorStreamFactory factory)
280             throws CompressorException, IOException {
281         return factory.createCompressorInputStream(
282                    new BufferedInputStream(new FileInputStream(
283                        getFile(resource))));
284     }
285 }
286