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