1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.util.zip;
18
19import java.io.ByteArrayOutputStream;
20import java.util.zip.Adler32;
21import java.util.zip.Deflater;
22import java.util.zip.Inflater;
23import junit.framework.TestCase;
24
25public class InflaterTest extends TestCase {
26    public void testDefaultDictionary() throws Exception {
27        assertRoundTrip(null);
28    }
29
30    public void testPresetCustomDictionary() throws Exception {
31        assertRoundTrip("dictionary".getBytes("UTF-8"));
32    }
33
34    private static void assertRoundTrip(byte[] dictionary) throws Exception {
35        // Construct a nice long input byte sequence.
36        String expected = makeString();
37        byte[] expectedBytes = expected.getBytes("UTF-8");
38
39        // Compress the bytes, using the passed-in dictionary (or no dictionary).
40        byte[] deflatedBytes = deflate(expectedBytes, dictionary);
41
42        // Get ready to decompress deflatedBytes back to the original bytes ...
43        Inflater inflater = new Inflater();
44        // We'll only supply the input a little bit at a time, so that zlib has to ask for more.
45        final int CHUNK_SIZE = 16;
46        int offset = 0;
47        inflater.setInput(deflatedBytes, offset, CHUNK_SIZE);
48        offset += CHUNK_SIZE;
49        // If we used a dictionary to compress, check that we're asked for that same dictionary.
50        if (dictionary != null) {
51            // 1. there's no data available immediately...
52            assertEquals(0, inflater.inflate(new byte[8]));
53            // 2. ...because you need a dictionary.
54            assertTrue(inflater.needsDictionary());
55            // 3. ...and that dictionary has the same Adler32 as the dictionary we used.
56            assertEquals(adler32(dictionary), inflater.getAdler());
57            inflater.setDictionary(dictionary);
58        }
59        // Do the actual decompression, now the dictionary's set up appropriately...
60        // We use a tiny output buffer to ensure that we call inflate multiple times, and
61        // a tiny input buffer to ensure that zlib has to ask for more input.
62        ByteArrayOutputStream inflatedBytes = new ByteArrayOutputStream();
63        byte[] buf = new byte[8];
64        while (inflatedBytes.size() != expectedBytes.length) {
65            if (inflater.needsInput()) {
66                int nextChunkByteCount = Math.min(CHUNK_SIZE, deflatedBytes.length - offset);
67                inflater.setInput(deflatedBytes, offset, nextChunkByteCount);
68                offset += nextChunkByteCount;
69            } else {
70                int inflatedByteCount = inflater.inflate(buf);
71                if (inflatedByteCount > 0) {
72                    inflatedBytes.write(buf, 0, inflatedByteCount);
73                }
74            }
75        }
76        inflater.end();
77
78        assertEquals(expected, new String(inflatedBytes.toByteArray(), "UTF-8"));
79    }
80
81    private static String makeString() {
82        StringBuilder sb = new StringBuilder();
83        for (int i = 0; i < 1024; ++i) {
84            // This is arbitrary but convenient in that it gives our string
85            // an easily-recognizable beginning and end.
86            sb.append(i + 1024);
87        }
88        return sb.toString();
89    }
90
91    /**
92     * http://code.google.com/p/android/issues/detail?id=11755
93     */
94    public void testEmptyFileAndEmptyBuffer() throws Exception {
95        byte[] emptyInput = deflate(new byte[0], null);
96        Inflater inflater = new Inflater();
97        inflater.setInput(emptyInput);
98        assertFalse(inflater.finished());
99        assertEquals(0, inflater.inflate(new byte[0], 0, 0));
100        assertTrue(inflater.finished());
101    }
102
103    private static byte[] deflate(byte[] input, byte[] dictionary) {
104        Deflater deflater = new Deflater();
105        if (dictionary != null) {
106            deflater.setDictionary(dictionary);
107        }
108        deflater.setInput(input);
109        deflater.finish();
110        ByteArrayOutputStream deflatedBytes = new ByteArrayOutputStream();
111        byte[] buf = new byte[8];
112        while (!deflater.finished()) {
113            int byteCount = deflater.deflate(buf);
114            deflatedBytes.write(buf, 0, byteCount);
115        }
116        deflater.end();
117        return deflatedBytes.toByteArray();
118    }
119
120    private static int adler32(byte[] bytes) {
121        Adler32 adler32 = new Adler32();
122        adler32.update(bytes);
123        return (int) adler32.getValue();
124    }
125
126    public void testInflaterCounts() throws Exception {
127        Inflater inflater = new Inflater();
128
129        byte[] decompressed = new byte[32];
130        byte[] compressed = deflate(new byte[] { 1, 2, 3}, null);
131        assertEquals(11, compressed.length);
132
133        // Feed in bytes [0, 5) to the first iteration.
134        inflater.setInput(compressed, 0, 5);
135        inflater.inflate(decompressed, 0, decompressed.length);
136        assertEquals(5, inflater.getBytesRead());
137        assertEquals(5, inflater.getTotalIn());
138        assertEquals(2, inflater.getBytesWritten());
139        assertEquals(2, inflater.getTotalOut());
140
141        // Feed in bytes [5, 11) to the second iteration.
142        assertEquals(true, inflater.needsInput());
143        inflater.setInput(compressed, 5, 6);
144        assertEquals(1, inflater.inflate(decompressed, 0, decompressed.length));
145        assertEquals(11, inflater.getBytesRead());
146        assertEquals(11, inflater.getTotalIn());
147        assertEquals(3, inflater.getBytesWritten());
148        assertEquals(3, inflater.getTotalOut());
149
150        inflater.reset();
151        assertEquals(0, inflater.getBytesRead());
152        assertEquals(0, inflater.getTotalIn());
153        assertEquals(0, inflater.getBytesWritten());
154        assertEquals(0, inflater.getTotalOut());
155    }
156}
157