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.ByteArrayInputStream; 20import java.io.ByteArrayOutputStream; 21import java.io.EOFException; 22import java.io.IOException; 23import java.io.OutputStream; 24import java.io.PipedInputStream; 25import java.io.PipedOutputStream; 26import java.lang.reflect.Field; 27import java.util.Arrays; 28import java.util.concurrent.Callable; 29import java.util.concurrent.ExecutorService; 30import java.util.concurrent.Executors; 31import java.util.zip.Deflater; 32import java.util.zip.DeflaterOutputStream; 33import java.util.zip.InflaterInputStream; 34import junit.framework.TestCase; 35 36public class DeflaterOutputStreamTest extends TestCase { 37 38 public void testSyncFlushEnabled() throws Exception { 39 InflaterInputStream in = createInflaterStream(true); 40 assertEquals(1, in.read()); 41 assertEquals(2, in.read()); 42 assertEquals(3, in.read()); 43 in.close(); 44 } 45 46 public void testSyncFlushDisabled() throws Exception { 47 InflaterInputStream in = createInflaterStream(false); 48 try { 49 in.read(); 50 fail(); 51 } catch (IOException expected) { 52 } 53 in.close(); 54 } 55 56 /** 57 * Creates an optionally-flushing deflater stream, writes some bytes to it, 58 * and flushes it. Returns an inflater stream that reads this deflater's 59 * output. 60 * 61 * <p>These bytes are written on a separate thread so that when the inflater 62 * stream is read, that read will fail when no bytes are available. Failing 63 * takes 3 seconds, co-ordinated by PipedInputStream's 'broken pipe' 64 * timeout. The 3 second delay is unfortunate but seems to be the easiest 65 * way demonstrate that data is unavailable. Ie. other techniques will cause 66 * the dry read to block indefinitely. 67 */ 68 private InflaterInputStream createInflaterStream(final boolean flushing) throws Exception { 69 ExecutorService executor = Executors.newSingleThreadExecutor(); 70 final PipedOutputStream pout = new PipedOutputStream(); 71 PipedInputStream pin = new PipedInputStream(pout); 72 73 executor.submit(new Callable<Void>() { 74 public Void call() throws Exception { 75 OutputStream out = new DeflaterOutputStream(pout, flushing); 76 out.write(1); 77 out.write(2); 78 out.write(3); 79 out.flush(); 80 return null; 81 } 82 }).get(); 83 executor.shutdown(); 84 85 return new InflaterInputStream(pin); 86 } 87 88 /** 89 * Confirm that a DeflaterOutputStream constructed with Deflater 90 * with flushParm == SYNC_FLUSH does not need to to be flushed. 91 * 92 * http://b/4005091 93 */ 94 public void testSyncFlushDeflater() throws Exception { 95 Deflater def = new Deflater(); 96 Field f = def.getClass().getDeclaredField("flushParm"); 97 f.setAccessible(true); 98 f.setInt(def, Deflater.SYNC_FLUSH); 99 100 final int deflaterBufferSize = 512; 101 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 102 DeflaterOutputStream dos = new DeflaterOutputStream(baos, def, deflaterBufferSize); 103 104 // make output buffer large enough that even if compressed it 105 // won't all fit within the deflaterBufferSize. 106 final int outputBufferSize = 128 * deflaterBufferSize; 107 byte[] output = new byte[outputBufferSize]; 108 for (int i = 0; i < output.length; i++) { 109 output[i] = (byte) i; 110 } 111 dos.write(output); 112 byte[] compressed = baos.toByteArray(); 113 // this main reason for this assert is to make sure that the 114 // compressed byte count is larger than the 115 // deflaterBufferSize. However, when the original bug exists, 116 // it will also fail because the compressed length will be 117 // exactly the length of the deflaterBufferSize. 118 assertTrue("compressed=" + compressed.length 119 + " but deflaterBufferSize=" + deflaterBufferSize, 120 compressed.length > deflaterBufferSize); 121 122 // assert that we returned data matches the input exactly. 123 ByteArrayInputStream bais = new ByteArrayInputStream(compressed); 124 InflaterInputStream iis = new InflaterInputStream(bais); 125 byte[] input = new byte[output.length]; 126 int total = 0; 127 while (true) { 128 int n = iis.read(input, total, input.length - total); 129 if (n == -1) { 130 break; 131 } 132 total += n; 133 if (total == input.length) { 134 try { 135 iis.read(); 136 fail(); 137 } catch (EOFException expected) { 138 break; 139 } 140 } 141 } 142 assertEquals(output.length, total); 143 assertTrue(Arrays.equals(input, output)); 144 145 // ensure Deflater.finish has not been called at any point 146 // during the test, since that would lead to the results being 147 // flushed even without SYNC_FLUSH being used 148 assertFalse(def.finished()); 149 } 150} 151