1/*
2 * Copyright (C) 2008 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 android.core;
18
19import junit.framework.TestCase;
20
21import java.io.UnsupportedEncodingException;
22import java.util.zip.DataFormatException;
23import java.util.zip.Deflater;
24import java.util.zip.Inflater;
25import android.test.suitebuilder.annotation.LargeTest;
26
27public class DeflateTest extends TestCase {
28
29    @LargeTest
30    public void testDeflate() throws Exception {
31        simpleTest();
32
33        bigTest(0, 1738149618);
34        bigTest(1, 934350518);
35        bigTest(2, -532869390);
36    }
37
38    /*
39     * Simple inflate/deflate test, taken from the reference docs for the
40     * Inflater/Deflater classes.
41     */
42    private void simpleTest()
43            throws UnsupportedEncodingException, DataFormatException {
44        // Encode a String into bytes
45        String inputString = "blahblahblah??";
46        byte[] input = inputString.getBytes("UTF-8");
47
48        // Compress the bytes
49        byte[] output = new byte[100];
50        Deflater compresser = new Deflater();
51        compresser.setInput(input);
52        compresser.finish();
53        int compressedDataLength = compresser.deflate(output);
54
55        // Decompress the bytes
56        Inflater decompresser = new Inflater();
57        decompresser.setInput(output, 0, compressedDataLength);
58        byte[] result = new byte[100];
59        int resultLength = decompresser.inflate(result);
60
61        // Decode the bytes into a String
62        String outputString = new String(result, 0, resultLength, "UTF-8");
63
64        assertEquals(inputString, outputString);
65        assertEquals(compresser.getAdler(), decompresser.getAdler());
66
67        decompresser.end();
68    }
69
70    /*
71     * "step" determines how compressible the data is.
72     *
73     * Note we must set "nowrap" to false, or the Adler-32 doesn't get
74     * computed.
75     */
76    private void bigTest(int step, int expectedAdler)
77            throws UnsupportedEncodingException, DataFormatException {
78        byte[] input = new byte[128 * 1024];
79        byte[] comp = new byte[128 * 1024 + 512];
80        byte[] output = new byte[128 * 1024 + 512];
81        Inflater inflater = new Inflater(false);
82        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false);
83
84        createSample(input, step);
85
86        compress(deflater, input, comp);
87        expand(inflater, comp, (int) deflater.getBytesWritten(), output);
88
89        assertEquals(inflater.getBytesWritten(), input.length);
90        assertEquals(deflater.getAdler(), inflater.getAdler());
91        assertEquals(deflater.getAdler(), expectedAdler);
92    }
93
94    /*
95     * Create a large data sample.
96     * stepStep = 0 --> >99% compression
97     * stepStep = 1 --> ~30% compression
98     * stepStep = 2 --> no compression
99     */
100    private void createSample(byte[] sample, int stepStep) {
101        byte val, step;
102        int i, j, offset;
103
104        assertTrue(sample.length >= 128 * 1024);
105
106        val = 0;
107        step = 1;
108        offset = 0;
109        for (i = 0; i < (128 * 1024) / 256; i++) {
110            for (j = 0; j < 256; j++) {
111                sample[offset++] = val;
112                val += step;
113            }
114
115            step += stepStep;
116        }
117    }
118
119    private static final int LOCAL_BUF_SIZE = 256;
120
121    /*
122     * Compress all data in "in" to "out".  We use a small window on input
123     * and output to exercise that part of the code.
124     *
125     * It's the caller's responsibility to ensure that "out" has enough
126     * space.
127     */
128    private void compress(Deflater deflater, byte[] inBuf, byte[] outBuf) {
129        int inCount = inBuf.length;        // use all
130        int inPosn;
131        int outPosn;
132
133        inPosn = outPosn = 0;
134
135        //System.out.println("### starting compress");
136
137        while (!deflater.finished()) {
138            int want = -1, got;
139
140            // only read if the input buffer is empty
141            if (deflater.needsInput() && inCount != 0) {
142                want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
143
144                deflater.setInput(inBuf, inPosn, want);
145
146                inCount -= want;
147                inPosn += want;
148                if (inCount == 0) {
149                    deflater.finish();
150                }
151            }
152
153            // deflate to current position in output buffer
154            int compCount;
155
156            compCount = deflater.deflate(outBuf, outPosn, LOCAL_BUF_SIZE);
157            outPosn += compCount;
158
159            //System.out.println("Compressed " + want + ", output " + compCount);
160        }
161    }
162
163    /*
164     * Expand data from "inBuf" to "outBuf".  Uses a small window to better
165     * exercise the code.
166     */
167    private void expand(Inflater inflater, byte[] inBuf, int inCount,
168            byte[] outBuf) throws DataFormatException {
169        int inPosn;
170        int outPosn;
171
172        inPosn = outPosn = 0;
173
174        //System.out.println("### starting expand, inCount is " + inCount);
175
176        while (!inflater.finished()) {
177            int want = -1, got;
178
179            // only read if the input buffer is empty
180            if (inflater.needsInput() && inCount != 0) {
181                want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
182
183                inflater.setInput(inBuf, inPosn, want);
184
185                inCount -= want;
186                inPosn += want;
187            }
188
189            // inflate to current position in output buffer
190            int compCount;
191
192            compCount = inflater.inflate(outBuf, outPosn, LOCAL_BUF_SIZE);
193            outPosn += compCount;
194
195            //System.out.println("Expanded " + want + ", output " + compCount);
196        }
197    }
198}
199
200