blob: f546214912cce82a3651dbaac7f53f85954c455f [file] [log] [blame]
/*
* 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.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static java.util.Arrays.asList;
import static okio.TestUtil.repeat;
import static okio.Util.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@RunWith(Parameterized.class)
public class BufferedSinkTest {
private interface Factory {
BufferedSink create(Buffer data);
}
// ANDROID-BEGIN
// @Parameterized.Parameters(name = "{0}")
// ANDROID-END
public static List<Object[]> parameters() {
return Arrays.asList(new Object[] {
new Factory() {
@Override public BufferedSink create(Buffer data) {
return data;
}
@Override public String toString() {
return "Buffer";
}
}
}, new Object[] {
new Factory() {
@Override public BufferedSink create(Buffer data) {
return new RealBufferedSink(data);
}
@Override public String toString() {
return "RealBufferedSink";
}
}
});
}
// ANDROID-BEGIN
// @Parameterized.Parameter
public Factory factory = (Factory) (parameters().get(0))[0];
// ANDROID-END
private Buffer data;
private BufferedSink sink;
@Before public void setUp() {
data = new Buffer();
sink = factory.create(data);
}
@Test public void writeNothing() throws IOException {
sink.writeUtf8("");
sink.flush();
assertEquals(0, data.size());
}
@Test public void writeBytes() throws Exception {
sink.writeByte(0xab);
sink.writeByte(0xcd);
sink.flush();
assertEquals("Buffer[size=2 data=abcd]", data.toString());
}
@Test public void writeLastByteInSegment() throws Exception {
sink.writeUtf8(repeat('a', Segment.SIZE - 1));
sink.writeByte(0x20);
sink.writeByte(0x21);
sink.flush();
assertEquals(asList(Segment.SIZE, 1), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1));
assertEquals("Buffer[size=2 data=2021]", data.toString());
}
@Test public void writeShort() throws Exception {
sink.writeShort(0xabcd);
sink.writeShort(0x4321);
sink.flush();
assertEquals("Buffer[size=4 data=abcd4321]", data.toString());
}
@Test public void writeShortLe() throws Exception {
sink.writeShortLe(0xabcd);
sink.writeShortLe(0x4321);
sink.flush();
assertEquals("Buffer[size=4 data=cdab2143]", data.toString());
}
@Test public void writeInt() throws Exception {
sink.writeInt(0xabcdef01);
sink.writeInt(0x87654321);
sink.flush();
assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void writeLastIntegerInSegment() throws Exception {
sink.writeUtf8(repeat('a', Segment.SIZE - 4));
sink.writeInt(0xabcdef01);
sink.writeInt(0x87654321);
sink.flush();
assertEquals(asList(Segment.SIZE, 4), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4));
assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void writeIntegerDoesNotQuiteFitInSegment() throws Exception {
sink.writeUtf8(repeat('a', Segment.SIZE - 3));
sink.writeInt(0xabcdef01);
sink.writeInt(0x87654321);
sink.flush();
assertEquals(asList(Segment.SIZE - 3, 8), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3));
assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void writeIntLe() throws Exception {
sink.writeIntLe(0xabcdef01);
sink.writeIntLe(0x87654321);
sink.flush();
assertEquals("Buffer[size=8 data=01efcdab21436587]", data.toString());
}
@Test public void writeLong() throws Exception {
sink.writeLong(0xabcdef0187654321L);
sink.writeLong(0xcafebabeb0b15c00L);
sink.flush();
assertEquals("Buffer[size=16 data=abcdef0187654321cafebabeb0b15c00]", data.toString());
}
@Test public void writeLongLe() throws Exception {
sink.writeLongLe(0xabcdef0187654321L);
sink.writeLongLe(0xcafebabeb0b15c00L);
sink.flush();
assertEquals("Buffer[size=16 data=2143658701efcdab005cb1b0bebafeca]", data.toString());
}
@Test public void writeStringUtf8() throws IOException {
sink.writeUtf8("təˈranəˌsôr");
sink.flush();
assertEquals(ByteString.decodeHex("74c999cb8872616ec999cb8c73c3b472"), data.readByteString());
}
@Test public void writeSubstringUtf8() throws IOException {
sink.writeUtf8("təˈranəˌsôr", 3, 7);
sink.flush();
assertEquals(ByteString.decodeHex("72616ec999"), data.readByteString());
}
@Test public void writeStringWithCharset() throws IOException {
sink.writeString("təˈranəˌsôr", Charset.forName("utf-32be"));
sink.flush();
assertEquals(ByteString.decodeHex("0000007400000259000002c800000072000000610000006e00000259"
+ "000002cc00000073000000f400000072"), data.readByteString());
}
@Test public void writeSubstringWithCharset() throws IOException {
sink.writeString("təˈranəˌsôr", 3, 7, Charset.forName("utf-32be"));
sink.flush();
assertEquals(ByteString.decodeHex("00000072000000610000006e00000259"), data.readByteString());
}
@Test public void writeAll() throws Exception {
Buffer source = new Buffer().writeUtf8("abcdef");
assertEquals(6, sink.writeAll(source));
assertEquals(0, source.size());
sink.flush();
assertEquals("abcdef", data.readUtf8());
}
@Test public void writeSource() throws Exception {
Buffer source = new Buffer().writeUtf8("abcdef");
// Force resolution of the Source method overload.
sink.write((Source) source, 4);
sink.flush();
assertEquals("abcd", data.readUtf8());
assertEquals("ef", source.readUtf8());
}
@Test public void writeSourceReadsFully() throws Exception {
Source source = new ForwardingSource(new Buffer()) {
@Override public long read(Buffer sink, long byteCount) throws IOException {
sink.writeUtf8("abcd");
return 4;
}
};
sink.write(source, 8);
sink.flush();
assertEquals("abcdabcd", data.readUtf8());
}
@Test public void writeSourcePropagatesEof() throws IOException {
Source source = new Buffer().writeUtf8("abcd");
try {
sink.write(source, 8);
fail();
} catch (EOFException expected) {
}
// Ensure that whatever was available was correctly written.
sink.flush();
assertEquals("abcd", data.readUtf8());
}
@Test public void writeSourceWithZeroIsNoOp() throws IOException {
// This test ensures that a zero byte count never calls through to read the source. It may be
// tied to something like a socket which will potentially block trying to read a segment when
// ultimately we don't want any data.
Source source = new ForwardingSource(new Buffer()) {
@Override public long read(Buffer sink, long byteCount) throws IOException {
throw new AssertionError();
}
};
sink.write(source, 0);
assertEquals(0, data.size());
}
@Test public void writeAllExhausted() throws Exception {
Buffer source = new Buffer();
assertEquals(0, sink.writeAll(source));
assertEquals(0, source.size());
}
@Test public void closeEmitsBufferedBytes() throws IOException {
sink.writeByte('a');
sink.close();
assertEquals('a', data.readByte());
}
@Test public void outputStream() throws Exception {
OutputStream out = sink.outputStream();
out.write('a');
out.write(repeat('b', 9998).getBytes(UTF_8));
out.write('c');
out.flush();
assertEquals("a" + repeat('b', 9998) + "c", data.readUtf8());
}
@Test public void outputStreamBounds() throws Exception {
OutputStream out = sink.outputStream();
try {
out.write(new byte[100], 50, 51);
fail();
} catch (ArrayIndexOutOfBoundsException expected) {
}
}
@Test public void longDecimalString() throws IOException {
assertLongDecimalString(0);
assertLongDecimalString(Long.MIN_VALUE);
assertLongDecimalString(Long.MAX_VALUE);
for (int i = 1; i < 20; i++) {
long value = BigInteger.valueOf(10L).pow(i).longValue();
assertLongDecimalString(value - 1);
assertLongDecimalString(value);
}
}
private void assertLongDecimalString(long value) throws IOException {
sink.writeDecimalLong(value).writeUtf8("zzz").flush();
String expected = Long.toString(value) + "zzz";
String actual = data.readUtf8();
assertEquals(value + " expected " + expected + " but was " + actual, actual, expected);
}
@Test public void longHexString() throws IOException {
assertLongHexString(0);
assertLongHexString(Long.MIN_VALUE);
assertLongHexString(Long.MAX_VALUE);
for (int i = 0; i < 16; i++) {
assertLongHexString((1 << i) - 1);
assertLongHexString(1 << i);
}
}
private void assertLongHexString(long value) throws IOException {
sink.writeHexadecimalUnsignedLong(value).writeUtf8("zzz").flush();
String expected = String.format("%x", value) + "zzz";
String actual = data.readUtf8();
assertEquals(value + " expected " + expected + " but was " + actual, actual, expected);
}
}