Home | History | Annotate | Download | only in zip
      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 
     17 package libcore.java.util.zip;
     18 
     19 import java.io.ByteArrayOutputStream;
     20 import java.util.zip.Adler32;
     21 import java.util.zip.Deflater;
     22 import java.util.zip.Inflater;
     23 import libcore.junit.junit3.TestCaseWithRules;
     24 import libcore.junit.util.ResourceLeakageDetector;
     25 import org.junit.Rule;
     26 import org.junit.rules.TestRule;
     27 
     28 public class InflaterTest extends TestCaseWithRules {
     29     @Rule
     30     public TestRule resourceLeakageDetectorRule = ResourceLeakageDetector.getRule();
     31 
     32     public void testDefaultDictionary() throws Exception {
     33         assertRoundTrip(null);
     34     }
     35 
     36     public void testPresetCustomDictionary() throws Exception {
     37         assertRoundTrip("dictionary".getBytes("UTF-8"));
     38     }
     39 
     40     private static void assertRoundTrip(byte[] dictionary) throws Exception {
     41         // Construct a nice long input byte sequence.
     42         String expected = makeString();
     43         byte[] expectedBytes = expected.getBytes("UTF-8");
     44 
     45         // Compress the bytes, using the passed-in dictionary (or no dictionary).
     46         byte[] deflatedBytes = deflate(expectedBytes, dictionary);
     47 
     48         // Get ready to decompress deflatedBytes back to the original bytes ...
     49         Inflater inflater = new Inflater();
     50         // We'll only supply the input a little bit at a time, so that zlib has to ask for more.
     51         final int CHUNK_SIZE = 16;
     52         int offset = 0;
     53         inflater.setInput(deflatedBytes, offset, CHUNK_SIZE);
     54         offset += CHUNK_SIZE;
     55         // If we used a dictionary to compress, check that we're asked for that same dictionary.
     56         if (dictionary != null) {
     57             // 1. there's no data available immediately...
     58             assertEquals(0, inflater.inflate(new byte[8]));
     59             // 2. ...because you need a dictionary.
     60             assertTrue(inflater.needsDictionary());
     61             // 3. ...and that dictionary has the same Adler32 as the dictionary we used.
     62             assertEquals(adler32(dictionary), inflater.getAdler());
     63             inflater.setDictionary(dictionary);
     64         }
     65         // Do the actual decompression, now the dictionary's set up appropriately...
     66         // We use a tiny output buffer to ensure that we call inflate multiple times, and
     67         // a tiny input buffer to ensure that zlib has to ask for more input.
     68         ByteArrayOutputStream inflatedBytes = new ByteArrayOutputStream();
     69         byte[] buf = new byte[8];
     70         while (inflatedBytes.size() != expectedBytes.length) {
     71             if (inflater.needsInput()) {
     72                 int nextChunkByteCount = Math.min(CHUNK_SIZE, deflatedBytes.length - offset);
     73                 inflater.setInput(deflatedBytes, offset, nextChunkByteCount);
     74                 offset += nextChunkByteCount;
     75             } else {
     76                 int inflatedByteCount = inflater.inflate(buf);
     77                 if (inflatedByteCount > 0) {
     78                     inflatedBytes.write(buf, 0, inflatedByteCount);
     79                 }
     80             }
     81         }
     82         inflater.end();
     83 
     84         assertEquals(expected, new String(inflatedBytes.toByteArray(), "UTF-8"));
     85     }
     86 
     87     private static String makeString() {
     88         StringBuilder sb = new StringBuilder();
     89         for (int i = 0; i < 1024; ++i) {
     90             // This is arbitrary but convenient in that it gives our string
     91             // an easily-recognizable beginning and end.
     92             sb.append(i + 1024);
     93         }
     94         return sb.toString();
     95     }
     96 
     97     /**
     98      * http://code.google.com/p/android/issues/detail?id=11755
     99      */
    100     public void testEmptyFileAndEmptyBuffer() throws Exception {
    101         byte[] emptyInput = deflate(new byte[0], null);
    102         Inflater inflater = new Inflater();
    103         inflater.setInput(emptyInput);
    104         assertFalse(inflater.finished());
    105         assertEquals(0, inflater.inflate(new byte[0], 0, 0));
    106         assertTrue(inflater.finished());
    107         inflater.end();
    108     }
    109 
    110     private static byte[] deflate(byte[] input, byte[] dictionary) {
    111         Deflater deflater = new Deflater();
    112         ByteArrayOutputStream deflatedBytes = new ByteArrayOutputStream();
    113         try {
    114             if (dictionary != null) {
    115                 deflater.setDictionary(dictionary);
    116             }
    117             deflater.setInput(input);
    118             deflater.finish();
    119             byte[] buf = new byte[8];
    120             while (!deflater.finished()) {
    121                 int byteCount = deflater.deflate(buf);
    122                 deflatedBytes.write(buf, 0, byteCount);
    123             }
    124         } finally {
    125             deflater.end();
    126         }
    127         return deflatedBytes.toByteArray();
    128     }
    129 
    130     private static int adler32(byte[] bytes) {
    131         Adler32 adler32 = new Adler32();
    132         adler32.update(bytes);
    133         return (int) adler32.getValue();
    134     }
    135 
    136     public void testInflaterCounts() throws Exception {
    137         Inflater inflater = new Inflater();
    138         byte[] decompressed = new byte[32];
    139         byte[] compressed = deflate(new byte[] { 1, 2, 3 }, null);
    140         assertEquals(11, compressed.length);
    141 
    142         // Feed in bytes [0, 5) to the first iteration.
    143         inflater.setInput(compressed, 0, 5);
    144         inflater.inflate(decompressed, 0, decompressed.length);
    145         assertEquals(5, inflater.getBytesRead());
    146         assertEquals(5, inflater.getTotalIn());
    147         assertEquals(2, inflater.getBytesWritten());
    148         assertEquals(2, inflater.getTotalOut());
    149 
    150         // Feed in bytes [5, 11) to the second iteration.
    151         assertEquals(true, inflater.needsInput());
    152         inflater.setInput(compressed, 5, 6);
    153         assertEquals(1, inflater.inflate(decompressed, 0, decompressed.length));
    154         assertEquals(11, inflater.getBytesRead());
    155         assertEquals(11, inflater.getTotalIn());
    156         assertEquals(3, inflater.getBytesWritten());
    157         assertEquals(3, inflater.getTotalOut());
    158 
    159         inflater.reset();
    160         assertEquals(0, inflater.getBytesRead());
    161         assertEquals(0, inflater.getTotalIn());
    162         assertEquals(0, inflater.getBytesWritten());
    163         assertEquals(0, inflater.getTotalOut());
    164         inflater.end();
    165     }
    166 }
    167