1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.harmony.tests.java.util.zip;
19
20import java.io.ByteArrayInputStream;
21import java.io.IOException;
22import java.io.InputStream;
23import java.util.Arrays;
24import java.util.zip.DataFormatException;
25import java.util.zip.Deflater;
26import java.util.zip.DeflaterInputStream;
27import libcore.io.Streams;
28import libcore.junit.junit3.TestCaseWithRules;
29import libcore.junit.util.ResourceLeakageDetector;
30import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
31import org.junit.Rule;
32import org.junit.rules.TestRule;
33
34public class DeflaterInputStreamTest extends TestCaseWithRules {
35    @Rule
36    public TestRule guardRule = ResourceLeakageDetector.getRule();
37
38    private static final String TEST_STR = "Hi,this is a test";
39
40    private static final byte[] TEST_STRING_DEFLATED_BYTES = {
41            120, -100, -13, -56, -44, 41, -55, -56, 44, 86,
42            0, -94, 68, -123, -110, -44, -30, 18, 0, 52,
43            34, 5, -13 };
44
45    private InputStream is;
46
47    @Override
48    protected void setUp() throws Exception {
49        super.setUp();
50        is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
51    }
52
53    @Override
54    protected void tearDown() throws Exception {
55        is.close();
56        super.tearDown();
57    }
58
59    /**
60     * DeflaterInputStream#available()
61     */
62    public void testAvailable() throws IOException {
63        byte[] buf = new byte[1024];
64        DeflaterInputStream dis = new DeflaterInputStream(is);
65        assertEquals(1, dis.available());
66        assertEquals(120, dis.read());
67        assertEquals(1, dis.available());
68        assertEquals(22, dis.read(buf, 0, 1024));
69        assertEquals(0, dis.available());
70        assertEquals(-1, dis.read());
71        assertEquals(0, dis.available());
72        dis.close();
73        try {
74            dis.available();
75            fail("should throw IOException");
76        } catch (IOException e) {
77            // expected
78        }
79    }
80
81    /**
82     * DeflaterInputStream#close()
83     */
84    public void testClose() throws IOException {
85        byte[] buf = new byte[1024];
86        DeflaterInputStream dis = new DeflaterInputStream(is);
87        assertEquals(1, dis.available());
88        dis.close();
89        try {
90            dis.available();
91            fail("should throw IOException");
92        } catch (IOException e) {
93            // expected
94        }
95        try {
96            dis.read(buf, 0, 1024);
97            fail("should throw IOException");
98        } catch (IOException e) {
99            // expected
100        }
101        // can close after close
102        dis.close();
103    }
104
105    /**
106     * DeflaterInputStream#mark()
107     */
108    public void testMark() throws IOException {
109        // mark do nothing
110        DeflaterInputStream dis = new DeflaterInputStream(is);
111        dis.mark(-1);
112        dis.mark(0);
113        dis.mark(1);
114        dis.close();
115        dis.mark(1);
116    }
117
118    /**
119     * DeflaterInputStream#markSupported()
120     */
121    public void testMarkSupported() throws IOException {
122        DeflaterInputStream dis = new DeflaterInputStream(is);
123        assertFalse(dis.markSupported());
124        dis.close();
125        assertFalse(dis.markSupported());
126    }
127
128    /**
129     * DeflaterInputStream#read()
130     */
131    public void testRead() throws IOException {
132        DeflaterInputStream dis = new DeflaterInputStream(is);
133        assertEquals(1, dis.available());
134        assertEquals(120, dis.read());
135        assertEquals(1, dis.available());
136        assertEquals(156, dis.read());
137        assertEquals(1, dis.available());
138        assertEquals(243, dis.read());
139        assertEquals(1, dis.available());
140        dis.close();
141        try {
142            dis.read();
143            fail("should throw IOException");
144        } catch (IOException e) {
145            // expected
146        }
147    }
148
149    public void testRead_golden() throws Exception {
150        try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
151            byte[] contents = Streams.readFully(dis);
152            assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, contents));
153        }
154
155        try (DeflaterInputStream dis = new DeflaterInputStream(
156                new ByteArrayInputStream(TEST_STR.getBytes("UTF-8")))) {
157            byte[] result = new byte[32];
158            int count = 0;
159            int bytesRead;
160            while ((bytesRead = dis.read(result, count, 4)) != -1) {
161                count += bytesRead;
162            }
163            assertEquals(23, count);
164            byte[] splicedResult = new byte[23];
165            System.arraycopy(result, 0, splicedResult, 0, 23);
166            assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, splicedResult));
167        }
168    }
169
170    public void testRead_leavesBufUnmodified() throws Exception {
171        DeflaterInputStreamWithPublicBuffer dis = new DeflaterInputStreamWithPublicBuffer(is);
172        byte[] contents = Streams.readFully(dis);
173        assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, contents));
174
175        // protected field buf is a part of the public API of this class.
176        // we guarantee that it's only used as an input buffer, and not for
177        // anything else.
178        byte[] buf = dis.getBuffer();
179        byte[] expected = TEST_STR.getBytes("UTF-8");
180
181        byte[] splicedBuf = new byte[expected.length];
182        System.arraycopy(buf, 0, splicedBuf, 0, splicedBuf.length);
183        assertTrue(Arrays.equals(expected, splicedBuf));
184    }
185
186    /**
187     * DeflaterInputStream#read(byte[], int, int)
188     */
189    public void testReadByteArrayIntInt() throws IOException {
190        byte[] buf1 = new byte[256];
191        byte[] buf2 = new byte[256];
192        try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
193            assertEquals(23, dis.read(buf1, 0, 256));
194        }
195
196        try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
197            assertEquals(8, dis.read(buf2, 0, 256));
198        }
199
200        is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
201        DeflaterInputStream dis = new DeflaterInputStream(is);
202        assertEquals(1, dis.available());
203        assertEquals(120, dis.read());
204        assertEquals(1, dis.available());
205        assertEquals(22, dis.read(buf2, 0, 256));
206        assertEquals(0, dis.available());
207        assertEquals(-1, dis.read());
208        assertEquals(0, dis.available());
209        try {
210            dis.read(buf1, 0, 512);
211            fail("should throw IndexOutOfBoundsException");
212        } catch (IndexOutOfBoundsException e) {
213            // expected
214        }
215        try {
216            dis.read(null, 0, 0);
217            fail("should throw NullPointerException");
218        } catch (NullPointerException e) {
219            // expected
220        }
221        try {
222            dis.read(null, -1, 0);
223            fail("should throw NullPointerException");
224        } catch (NullPointerException e) {
225            // expected
226        }
227        try {
228            dis.read(null, -1, -1);
229            fail("should throw NullPointerException");
230        } catch (NullPointerException e) {
231            // expected
232        }
233        try {
234            dis.read(buf1, -1, -1);
235            fail("should throw IndexOutOfBoundsException");
236        } catch (IndexOutOfBoundsException e) {
237            // expected
238        }
239        try {
240            dis.read(buf1, 0, -1);
241            fail("should throw IndexOutOfBoundsException");
242        } catch (IndexOutOfBoundsException e) {
243            // expected
244        }
245        dis.close();
246        try {
247            dis.read(buf1, 0, 512);
248            fail("should throw IOException");
249        } catch (IOException e) {
250            // expected
251        }
252        try {
253            dis.read(buf1, 0, 1);
254            fail("should throw IOException");
255        } catch (IOException e) {
256            // expected
257        }
258        try {
259            dis.read(null, 0, 0);
260            fail("should throw IOException");
261        } catch (IOException e) {
262            // expected
263        }
264        try {
265            dis.read(null, -1, 0);
266            fail("should throw IOException");
267        } catch (IOException e) {
268            // expected
269        }
270        try {
271            dis.read(null, -1, -1);
272            fail("should throw IOException");
273        } catch (IOException e) {
274            // expected
275        }
276        try {
277            dis.read(buf1, -1, -1);
278            fail("should throw IOException");
279        } catch (IOException e) {
280            // expected
281        }
282        try {
283            dis.read(buf1, 0, -1);
284            fail("should throw IOException");
285        } catch (IOException e) {
286            // expected
287        }
288    }
289
290    /**
291     * DeflaterInputStream#reset()
292     */
293    public void testReset() throws IOException {
294        DeflaterInputStream dis = new DeflaterInputStream(is);
295        try {
296            dis.reset();
297            fail("should throw IOException");
298        } catch (IOException e) {
299            // expected
300        }
301        dis.close();
302        try {
303            dis.reset();
304            fail("should throw IOException");
305        } catch (IOException e) {
306            // expected
307        }
308    }
309
310    /**
311     * DeflaterInputStream#skip()
312     */
313    public void testSkip() throws IOException {
314        byte[] buf = new byte[1024];
315        try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
316            assertEquals(1, dis.available());
317            dis.skip(1);
318            assertEquals(1, dis.available());
319            assertEquals(22, dis.read(buf, 0, 1024));
320            assertEquals(0, dis.available());
321            assertEquals(0, dis.available());
322            is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
323        }
324
325        is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
326        try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
327            assertEquals(23, dis.skip(Long.MAX_VALUE));
328            assertEquals(0, dis.available());
329        }
330
331        DeflaterInputStream dis = new DeflaterInputStream(is);
332        assertEquals(1, dis.available());
333        dis.skip(56);
334        assertEquals(0, dis.available());
335        assertEquals(-1, dis.read(buf, 0, 1024));
336
337        assertEquals(0, dis.available());
338        // can still skip
339        dis.skip(1);
340        dis.close();
341        try {
342            dis.skip(1);
343            fail("should throw IOException");
344        } catch (IOException e) {
345            // expected
346        }
347    }
348
349    /**
350     * DeflaterInputStream#DeflaterInputStream(InputStream)
351     */
352    @DisableResourceLeakageDetection(
353            why = "DeflaterInputStream does not clean up the default Deflater created in the"
354                    + " constructor if the constructor fails; i.e. constructor calls"
355                    + " this(..., new Deflater(), ...) and that constructor fails but does not know"
356                    + " that it needs to call Deflater.end() as the caller has no access to it",
357            bug = "31798154")
358    public void testDeflaterInputStreamInputStream() throws IOException {
359        // ok
360        new DeflaterInputStream(is).close();
361        // fail
362        try {
363            new DeflaterInputStream(null);
364            fail("should throw NullPointerException");
365        } catch (NullPointerException e) {
366            // expected
367        }
368    }
369
370    /**
371     * DataFormatException#DataFormatException()
372     */
373    public void testDataFormatException() {
374        new DataFormatException();
375    }
376
377    /**
378     * DeflaterInputStream#DeflaterInputStream(InputStream, Deflater)
379     */
380    public void testDeflaterInputStreamInputStreamDeflater() throws IOException {
381        // ok
382        Deflater deflater = new Deflater();
383        try {
384            new DeflaterInputStream(is, deflater).close();
385            // fail
386            try {
387                new DeflaterInputStream(is, null);
388                fail("should throw NullPointerException");
389            } catch (NullPointerException e) {
390                // expected
391            }
392            try {
393                new DeflaterInputStream(null, deflater);
394                fail("should throw NullPointerException");
395            } catch (NullPointerException e) {
396                // expected
397            }
398        } finally {
399            deflater.end();
400        }
401    }
402
403    /**
404     * DeflaterInputStream#DeflaterInputStream(InputStream, Deflater, int)
405     */
406    public void testDeflaterInputStreamInputStreamDeflaterInt() {
407        // ok
408        Deflater deflater = new Deflater();
409        try {
410            new DeflaterInputStream(is, deflater, 1024);
411            // fail
412            try {
413                new DeflaterInputStream(is, null, 1024);
414                fail("should throw NullPointerException");
415            } catch (NullPointerException e) {
416                // expected
417            }
418            try {
419                new DeflaterInputStream(null, deflater, 1024);
420                fail("should throw NullPointerException");
421            } catch (NullPointerException e) {
422                // expected
423            }
424            try {
425                new DeflaterInputStream(is, deflater, -1);
426                fail("should throw IllegalArgumentException");
427            } catch (IllegalArgumentException e) {
428                // expected
429            }
430            try {
431                new DeflaterInputStream(null, deflater, -1);
432                fail("should throw NullPointerException");
433            } catch (NullPointerException e) {
434                // expected
435            }
436            try {
437                new DeflaterInputStream(is, null, -1);
438                fail("should throw NullPointerException");
439            } catch (NullPointerException e) {
440                // expected
441            }
442        } finally {
443            deflater.end();
444        }
445    }
446
447    public static final class DeflaterInputStreamWithPublicBuffer extends DeflaterInputStream {
448
449        public DeflaterInputStreamWithPublicBuffer(InputStream in) {
450            super(in);
451        }
452
453        public byte[] getBuffer() {
454            return buf;
455        }
456    }
457}
458