diff options
Diffstat (limited to 'okio/src/commonTest/kotlin/okio/AbstractBufferedSinkTest.kt')
-rw-r--r-- | okio/src/commonTest/kotlin/okio/AbstractBufferedSinkTest.kt | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/okio/src/commonTest/kotlin/okio/AbstractBufferedSinkTest.kt b/okio/src/commonTest/kotlin/okio/AbstractBufferedSinkTest.kt new file mode 100644 index 00000000..49bff8d9 --- /dev/null +++ b/okio/src/commonTest/kotlin/okio/AbstractBufferedSinkTest.kt @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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 okio.ByteString.Companion.decodeHex +import okio.ByteString.Companion.encodeUtf8 +import kotlin.math.pow +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +class BufferSinkTest : AbstractBufferedSinkTest(BufferedSinkFactory.BUFFER) +class RealBufferedSinkTest : AbstractBufferedSinkTest(BufferedSinkFactory.REAL_BUFFERED_SINK) + +abstract class AbstractBufferedSinkTest internal constructor( + factory: BufferedSinkFactory +) { + private val data: Buffer = Buffer() + private val sink: BufferedSink = factory.create(data) + + @Test fun writeNothing() { + sink.writeUtf8("") + sink.flush() + assertEquals(0, data.size) + } + + @Test fun writeBytes() { + sink.writeByte(0xab) + sink.writeByte(0xcd) + sink.flush() + assertEquals("[hex=abcd]", data.toString()) + } + + @Test fun writeLastByteInSegment() { + sink.writeUtf8("a".repeat(Segment.SIZE - 1)) + sink.writeByte(0x20) + sink.writeByte(0x21) + sink.flush() + assertEquals(listOf(Segment.SIZE, 1), segmentSizes(data)) + assertEquals("a".repeat(Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1L)) + assertEquals("[text= !]", data.toString()) + } + + @Test fun writeShort() { + sink.writeShort(0xabcd) + sink.writeShort(0x4321) + sink.flush() + assertEquals("[hex=abcd4321]", data.toString()) + } + + @Test fun writeShortLe() { + sink.writeShortLe(0xcdab) + sink.writeShortLe(0x2143) + sink.flush() + assertEquals("[hex=abcd4321]", data.toString()) + } + + @Test fun writeInt() { + sink.writeInt(-0x543210ff) + sink.writeInt(-0x789abcdf) + sink.flush() + assertEquals("[hex=abcdef0187654321]", data.toString()) + } + + @Test fun writeLastIntegerInSegment() { + sink.writeUtf8("a".repeat(Segment.SIZE - 4)) + sink.writeInt(-0x543210ff) + sink.writeInt(-0x789abcdf) + sink.flush() + assertEquals(listOf(Segment.SIZE, 4), segmentSizes(data)) + assertEquals("a".repeat(Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4L)) + assertEquals("[hex=abcdef0187654321]", data.toString()) + } + + @Test fun writeIntegerDoesNotQuiteFitInSegment() { + sink.writeUtf8("a".repeat(Segment.SIZE - 3)) + sink.writeInt(-0x543210ff) + sink.writeInt(-0x789abcdf) + sink.flush() + assertEquals(listOf(Segment.SIZE - 3, 8), segmentSizes(data)) + assertEquals("a".repeat(Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3L)) + assertEquals("[hex=abcdef0187654321]", data.toString()) + } + + @Test fun writeIntLe() { + sink.writeIntLe(-0x543210ff) + sink.writeIntLe(-0x789abcdf) + sink.flush() + assertEquals("[hex=01efcdab21436587]", data.toString()) + } + + @Test fun writeLong() { + sink.writeLong(-0x543210fe789abcdfL) + sink.writeLong(-0x350145414f4ea400L) + sink.flush() + assertEquals("[hex=abcdef0187654321cafebabeb0b15c00]", data.toString()) + } + + @Test fun writeLongLe() { + sink.writeLongLe(-0x543210fe789abcdfL) + sink.writeLongLe(-0x350145414f4ea400L) + sink.flush() + assertEquals("[hex=2143658701efcdab005cb1b0bebafeca]", data.toString()) + } + + @Test fun writeByteString() { + sink.write("təˈranəˌsôr".encodeUtf8()) + sink.flush() + assertEquals("74c999cb8872616ec999cb8c73c3b472".decodeHex(), data.readByteString()) + } + + @Test fun writeByteStringOffset() { + sink.write("təˈranəˌsôr".encodeUtf8(), 5, 5) + sink.flush() + assertEquals("72616ec999".decodeHex(), data.readByteString()) + } + + @Test fun writeSegmentedByteString() { + sink.write(Buffer().write("təˈranəˌsôr".encodeUtf8()).snapshot()) + sink.flush() + assertEquals("74c999cb8872616ec999cb8c73c3b472".decodeHex(), data.readByteString()) + } + + @Test fun writeSegmentedByteStringOffset() { + sink.write(Buffer().write("təˈranəˌsôr".encodeUtf8()).snapshot(), 5, 5) + sink.flush() + assertEquals("72616ec999".decodeHex(), data.readByteString()) + } + + @Test fun writeStringUtf8() { + sink.writeUtf8("təˈranəˌsôr") + sink.flush() + assertEquals("74c999cb8872616ec999cb8c73c3b472".decodeHex(), data.readByteString()) + } + + @Test fun writeSubstringUtf8() { + sink.writeUtf8("təˈranəˌsôr", 3, 7) + sink.flush() + assertEquals("72616ec999".decodeHex(), data.readByteString()) + } + + @Test fun writeAll() { + val source = Buffer().writeUtf8("abcdef") + + assertEquals(6, sink.writeAll(source)) + assertEquals(0, source.size) + sink.flush() + assertEquals("abcdef", data.readUtf8()) + } + + @Test fun writeSource() { + val source = Buffer().writeUtf8("abcdef") + + // Force resolution of the Source method overload. + sink.write(source as Source, 4) + sink.flush() + assertEquals("abcd", data.readUtf8()) + assertEquals("ef", source.readUtf8()) + } + + @Test fun writeSourceReadsFully() { + val source = object : Source by Buffer() { + override fun read(sink: Buffer, byteCount: Long): Long { + sink.writeUtf8("abcd") + return 4 + } + } + + sink.write(source, 8) + sink.flush() + assertEquals("abcdabcd", data.readUtf8()) + } + + @Test fun writeSourcePropagatesEof() { + val source: Source = Buffer().writeUtf8("abcd") + + assertFailsWith<EOFException> { + sink.write(source, 8) + } + + // Ensure that whatever was available was correctly written. + sink.flush() + assertEquals("abcd", data.readUtf8()) + } + + @Test fun writeSourceWithZeroIsNoOp() { + // 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. + val source = object : Source by Buffer() { + override fun read(sink: Buffer, byteCount: Long): Long { + throw AssertionError() + } + } + sink.write(source, 0) + assertEquals(0, data.size) + } + + @Test fun writeAllExhausted() { + val source = Buffer() + assertEquals(0, sink.writeAll(source)) + assertEquals(0, source.size) + } + + @Test fun closeEmitsBufferedBytes() { + sink.writeByte('a'.toInt()) + sink.close() + assertEquals('a', data.readByte().toChar()) + } + + @Test fun longDecimalString() { + assertLongDecimalString(0) + assertLongDecimalString(Long.MIN_VALUE) + assertLongDecimalString(Long.MAX_VALUE) + + for (i in 1..19) { + val value = 10.0.pow(i).toLong() + assertLongDecimalString(value - 1) + assertLongDecimalString(value) + } + } + + private fun assertLongDecimalString(value: Long) { + sink.writeDecimalLong(value).writeUtf8("zzz").flush() + val expected = "${value}zzz" + val actual = data.readUtf8() + assertEquals(expected, actual, "$value expected $expected but was $actual") + } + + @Test fun longHexString() { + assertLongHexString(0) + assertLongHexString(Long.MIN_VALUE) + assertLongHexString(Long.MAX_VALUE) + + for (i in 0..62) { + assertLongHexString((1L shl i) - 1) + assertLongHexString(1L shl i) + } + } + + private fun assertLongHexString(value: Long) { + sink.writeHexadecimalUnsignedLong(value).writeUtf8("zzz").flush() + val expected = "${value.toHexString()}zzz" + val actual = data.readUtf8() + assertEquals(expected, actual, "$value expected $expected but was $actual") + } +} |