1cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson/* 2cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * Copyright (C) 2010 The Android Open Source Project 3cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * 4cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * you may not use this file except in compliance with the License. 6cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * You may obtain a copy of the License at 7cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * 8cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * 10cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * Unless required by applicable law or agreed to in writing, software 11cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * See the License for the specific language governing permissions and 14cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * limitations under the License. 15cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson */ 16cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.util.zip; 18cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 19a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstromimport java.io.ByteArrayInputStream; 20a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstromimport java.io.ByteArrayOutputStream; 21a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstromimport java.io.EOFException; 22cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.io.IOException; 2327604018f783bf6354a13870b3e7785edca69b5fPaul Duffinimport java.io.InputStream; 24cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.io.OutputStream; 25cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.io.PipedInputStream; 26cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.io.PipedOutputStream; 278601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstromimport java.util.Arrays; 28cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.util.concurrent.Callable; 29cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.util.concurrent.ExecutorService; 30cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilsonimport java.util.concurrent.Executors; 31a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstromimport java.util.zip.Deflater; 324557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.util.zip.DeflaterOutputStream; 3335f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughesimport java.util.zip.GZIPInputStream; 3435f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughesimport java.util.zip.GZIPOutputStream; 354557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.util.zip.InflaterInputStream; 3627604018f783bf6354a13870b3e7785edca69b5fPaul Duffinimport libcore.junit.junit3.TestCaseWithRules; 3727604018f783bf6354a13870b3e7785edca69b5fPaul Duffinimport libcore.junit.util.ResourceLeakageDetector; 3827604018f783bf6354a13870b3e7785edca69b5fPaul Duffinimport org.junit.Rule; 3927604018f783bf6354a13870b3e7785edca69b5fPaul Duffinimport org.junit.rules.TestRule; 40cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 4127604018f783bf6354a13870b3e7785edca69b5fPaul Duffinpublic class DeflaterOutputStreamTest extends TestCaseWithRules { 4227604018f783bf6354a13870b3e7785edca69b5fPaul Duffin @Rule 4327604018f783bf6354a13870b3e7785edca69b5fPaul Duffin public TestRule guardRule = ResourceLeakageDetector.getRule(); 44cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 45cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson public void testSyncFlushEnabled() throws Exception { 4635f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes InputStream in = createInflaterStream(DeflaterOutputStream.class, true); 47cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson assertEquals(1, in.read()); 48cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson assertEquals(2, in.read()); 49cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson assertEquals(3, in.read()); 50a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom in.close(); 51cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } 52cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 53cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson public void testSyncFlushDisabled() throws Exception { 5435f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes InputStream in = createInflaterStream(DeflaterOutputStream.class, false); 55cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson try { 56cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson in.read(); 57cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson fail(); 58cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } catch (IOException expected) { 59cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } 60a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom in.close(); 61cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } 62cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 63cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson /** 64cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * Creates an optionally-flushing deflater stream, writes some bytes to it, 65cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * and flushes it. Returns an inflater stream that reads this deflater's 66cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * output. 67cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * 68cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * <p>These bytes are written on a separate thread so that when the inflater 69cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * stream is read, that read will fail when no bytes are available. Failing 70cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * takes 3 seconds, co-ordinated by PipedInputStream's 'broken pipe' 71cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * timeout. The 3 second delay is unfortunate but seems to be the easiest 72cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * way demonstrate that data is unavailable. Ie. other techniques will cause 73cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson * the dry read to block indefinitely. 74cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson */ 7535f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes static InputStream createInflaterStream(final Class<?> c, final boolean flushing) throws Exception { 76cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson ExecutorService executor = Executors.newSingleThreadExecutor(); 77cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson final PipedOutputStream pout = new PipedOutputStream(); 78cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson PipedInputStream pin = new PipedInputStream(pout); 79cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 80cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson executor.submit(new Callable<Void>() { 81cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson public Void call() throws Exception { 8235f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes OutputStream out; 8335f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes if (c == DeflaterOutputStream.class) { 8435f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes out = new DeflaterOutputStream(pout, flushing); 8535f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } else if (c == GZIPOutputStream.class) { 8635f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes out = new GZIPOutputStream(pout, flushing); 8735f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } else { 8835f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes throw new AssertionError(); 8935f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } 90cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson out.write(1); 91cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson out.write(2); 92cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson out.write(3); 93cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson out.flush(); 94cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson return null; 95cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } 96cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson }).get(); 97cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson executor.shutdown(); 98cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson 9935f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes if (c == DeflaterOutputStream.class) { 10035f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes return new InflaterInputStream(pin); 10135f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } else if (c == GZIPOutputStream.class) { 10235f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes return new GZIPInputStream(pin); 10335f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } else { 10435f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes throw new AssertionError(); 10535f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes } 106cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson } 107a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom 1083e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath static class FlushingDeflater extends Deflater { 1093e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath @Override 1103e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath public int deflate(byte[] buf, int offset, int byteCount) { 1113e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath return super.deflate(buf, offset, byteCount, Deflater.SYNC_FLUSH); 1123e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath } 1133e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath } 1143e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath 115a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom /** 116a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom * Confirm that a DeflaterOutputStream constructed with Deflater 117a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom * with flushParm == SYNC_FLUSH does not need to to be flushed. 118a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom * 1198601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom * http://b/4005091 120a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom */ 121a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom public void testSyncFlushDeflater() throws Exception { 1223e2415c8a33ad147352176a0e98e43a8bbd5fb11Narayan Kamath Deflater def = new FlushingDeflater(); 123a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom final int deflaterBufferSize = 512; 124a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom ByteArrayOutputStream baos = new ByteArrayOutputStream(); 125a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom DeflaterOutputStream dos = new DeflaterOutputStream(baos, def, deflaterBufferSize); 126a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom 127a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom // make output buffer large enough that even if compressed it 128a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom // won't all fit within the deflaterBufferSize. 129a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom final int outputBufferSize = 128 * deflaterBufferSize; 130a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom byte[] output = new byte[outputBufferSize]; 131a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom for (int i = 0; i < output.length; i++) { 132a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom output[i] = (byte) i; 133a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 134a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom dos.write(output); 135a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom byte[] compressed = baos.toByteArray(); 1368601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // this main reason for this assert is to make sure that the 1378601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // compressed byte count is larger than the 1388601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // deflaterBufferSize. However, when the original bug exists, 1398601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // it will also fail because the compressed length will be 1408601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // exactly the length of the deflaterBufferSize. 141a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom assertTrue("compressed=" + compressed.length 142a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom + " but deflaterBufferSize=" + deflaterBufferSize, 143a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom compressed.length > deflaterBufferSize); 144a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom 1458601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // assert that we returned data matches the input exactly. 146a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom ByteArrayInputStream bais = new ByteArrayInputStream(compressed); 147a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom InflaterInputStream iis = new InflaterInputStream(bais); 148a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom byte[] input = new byte[output.length]; 149a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom int total = 0; 150a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom while (true) { 151a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom int n = iis.read(input, total, input.length - total); 152a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom if (n == -1) { 153a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom break; 154a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 155a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom total += n; 156a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom if (total == input.length) { 157a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom try { 158a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom iis.read(); 159a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom fail(); 160a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } catch (EOFException expected) { 161a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom break; 162a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 163a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 164a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 165a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom assertEquals(output.length, total); 1668601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom assertTrue(Arrays.equals(input, output)); 1678601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom 1688601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // ensure Deflater.finish has not been called at any point 1698601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // during the test, since that would lead to the results being 1708601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom // flushed even without SYNC_FLUSH being used 1718601d6b5872167f20f3ab845160ae7f9e0fad94bBrian Carlstrom assertFalse(def.finished()); 17235f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes 17335f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes // Quieten CloseGuard. 17435f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes def.end(); 17535f9da25ee063a0d0c32f7246b466cff8e57c9eeElliott Hughes iis.close(); 176a321720e459ae0d7fc403d112f2e974102a59d9fBrian Carlstrom } 177cf900b4862df0e261b3cce2195ff0654124ad7dbJesse Wilson} 178