| /* |
| * Copyright (C) 2014 Square, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package okio; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.zip.Deflater; |
| import java.util.zip.Inflater; |
| import java.util.zip.InflaterInputStream; |
| import org.junit.Test; |
| |
| import static okio.TestUtil.randomBytes; |
| import static okio.TestUtil.repeat; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.fail; |
| |
| public final class DeflaterSinkTest { |
| @Test public void deflateWithClose() throws Exception { |
| Buffer data = new Buffer(); |
| String original = "They're moving in herds. They do move in herds."; |
| data.writeUtf8(original); |
| Buffer sink = new Buffer(); |
| DeflaterSink deflaterSink = new DeflaterSink(sink, new Deflater()); |
| deflaterSink.write(data, data.size()); |
| deflaterSink.close(); |
| Buffer inflated = inflate(sink); |
| assertEquals(original, inflated.readUtf8()); |
| } |
| |
| @Test public void deflateWithSyncFlush() throws Exception { |
| String original = "Yes, yes, yes. That's why we're taking extreme precautions."; |
| Buffer data = new Buffer(); |
| data.writeUtf8(original); |
| Buffer sink = new Buffer(); |
| DeflaterSink deflaterSink = new DeflaterSink(sink, new Deflater()); |
| deflaterSink.write(data, data.size()); |
| deflaterSink.flush(); |
| Buffer inflated = inflate(sink); |
| assertEquals(original, inflated.readUtf8()); |
| } |
| |
| @Test public void deflateWellCompressed() throws IOException { |
| String original = repeat('a', 1024 * 1024); |
| Buffer data = new Buffer(); |
| data.writeUtf8(original); |
| Buffer sink = new Buffer(); |
| DeflaterSink deflaterSink = new DeflaterSink(sink, new Deflater()); |
| deflaterSink.write(data, data.size()); |
| deflaterSink.close(); |
| Buffer inflated = inflate(sink); |
| assertEquals(original, inflated.readUtf8()); |
| } |
| |
| @Test public void deflatePoorlyCompressed() throws IOException { |
| ByteString original = randomBytes(1024 * 1024); |
| Buffer data = new Buffer(); |
| data.write(original); |
| Buffer sink = new Buffer(); |
| DeflaterSink deflaterSink = new DeflaterSink(sink, new Deflater()); |
| deflaterSink.write(data, data.size()); |
| deflaterSink.close(); |
| Buffer inflated = inflate(sink); |
| assertEquals(original, inflated.readByteString()); |
| } |
| |
| @Test public void multipleSegmentsWithoutCompression() throws IOException { |
| Buffer buffer = new Buffer(); |
| Deflater deflater = new Deflater(); |
| deflater.setLevel(Deflater.NO_COMPRESSION); |
| DeflaterSink deflaterSink = new DeflaterSink(buffer, deflater); |
| int byteCount = Segment.SIZE * 4; |
| deflaterSink.write(new Buffer().writeUtf8(repeat('a', byteCount)), byteCount); |
| deflaterSink.close(); |
| assertEquals(repeat('a', byteCount), inflate(buffer).readUtf8(byteCount)); |
| } |
| |
| @Test public void deflateIntoNonemptySink() throws Exception { |
| String original = "They're moving in herds. They do move in herds."; |
| |
| // Exercise all possible offsets for the outgoing segment. |
| for (int i = 0; i < Segment.SIZE; i++) { |
| Buffer data = new Buffer().writeUtf8(original); |
| Buffer sink = new Buffer().writeUtf8(repeat('a', i)); |
| |
| DeflaterSink deflaterSink = new DeflaterSink(sink, new Deflater()); |
| deflaterSink.write(data, data.size()); |
| deflaterSink.close(); |
| |
| sink.skip(i); |
| Buffer inflated = inflate(sink); |
| assertEquals(original, inflated.readUtf8()); |
| } |
| } |
| |
| /** |
| * This test deflates a single segment of without compression because that's |
| * the easiest way to force close() to emit a large amount of data to the |
| * underlying sink. |
| */ |
| @Test public void closeWithExceptionWhenWritingAndClosing() throws IOException { |
| MockSink mockSink = new MockSink(); |
| mockSink.scheduleThrow(0, new IOException("first")); |
| mockSink.scheduleThrow(1, new IOException("second")); |
| Deflater deflater = new Deflater(); |
| deflater.setLevel(Deflater.NO_COMPRESSION); |
| DeflaterSink deflaterSink = new DeflaterSink(mockSink, deflater); |
| deflaterSink.write(new Buffer().writeUtf8(repeat('a', Segment.SIZE)), Segment.SIZE); |
| try { |
| deflaterSink.close(); |
| fail(); |
| } catch (IOException expected) { |
| assertEquals("first", expected.getMessage()); |
| } |
| mockSink.assertLogContains("close()"); |
| } |
| |
| /** |
| * Uses streaming decompression to inflate {@code deflated}. The input must |
| * either be finished or have a trailing sync flush. |
| */ |
| private Buffer inflate(Buffer deflated) throws IOException { |
| InputStream deflatedIn = deflated.inputStream(); |
| Inflater inflater = new Inflater(); |
| InputStream inflatedIn = new InflaterInputStream(deflatedIn, inflater); |
| Buffer result = new Buffer(); |
| byte[] buffer = new byte[8192]; |
| while (!inflater.needsInput() || deflated.size() > 0 || deflatedIn.available() > 0) { |
| int count = inflatedIn.read(buffer, 0, buffer.length); |
| if (count != -1) { |
| result.write(buffer, 0, count); |
| } |
| } |
| return result; |
| } |
| } |