diff --git a/app/src/main/java/de/kuschku/quasseldroid/protocol/io/CoroutineChannel.kt b/app/src/main/java/de/kuschku/quasseldroid/protocol/io/CoroutineChannel.kt index d400951e538f7f433f402f39c9f3bcc16daf7ea0..a2d3b88db5646033832beaac0250d6435b7b7a9a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/protocol/io/CoroutineChannel.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/protocol/io/CoroutineChannel.kt @@ -20,7 +20,6 @@ package de.kuschku.quasseldroid.protocol.io import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print import de.kuschku.quasseldroid.util.TlsInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher @@ -67,12 +66,11 @@ class CoroutineChannel { } suspend fun write(buffer: ByteBuffer): Int = runInterruptible(writeContext) { - buffer.print() this.channel.write(buffer) } suspend fun write(chainedBuffer: ChainedByteBuffer) { - for (buffer in chainedBuffer.buffers()) { + for (buffer in chainedBuffer.iterator()) { write(buffer) } } diff --git a/app/src/test/java/de/kuschku/quasseldroid/ExampleUnitTest.kt b/app/src/test/java/de/kuschku/quasseldroid/ExampleUnitTest.kt index dae870cd4367beb1be3a6640c9a1b923eeed424a..6a9c5578cea3d55572cc32743ceff96868b921a6 100644 --- a/app/src/test/java/de/kuschku/quasseldroid/ExampleUnitTest.kt +++ b/app/src/test/java/de/kuschku/quasseldroid/ExampleUnitTest.kt @@ -3,6 +3,7 @@ package de.kuschku.quasseldroid import de.kuschku.libquassel.protocol.connection.ProtocolInfoSerializer import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer +import de.kuschku.libquassel.protocol.io.contentToString import de.kuschku.libquassel.protocol.messages.handshake.ClientInit import de.kuschku.libquassel.protocol.serializers.HandshakeSerializers import de.kuschku.libquassel.protocol.serializers.handshake.ClientInitAckSerializer @@ -68,6 +69,7 @@ class ExampleUnitTest { channel.write(sizeBuffer) sizeBuffer.clear() } + println(sendBuffer.toBuffer().contentToString()) channel.write(sendBuffer) channel.flush() sendBuffer.clear() diff --git a/coverage-annotations/build.gradle.kts b/coverage-annotations/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..82b248afb0c354fe9f42a4b998f09abe724daf33 --- /dev/null +++ b/coverage-annotations/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + kotlin("jvm") +} + +dependencies { + implementation(kotlin("stdlib")) +} diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoders.kt b/coverage-annotations/src/main/kotlin/de/kuschku/codecoverage/Generated.kt similarity index 61% rename from protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoders.kt rename to coverage-annotations/src/main/kotlin/de/kuschku/codecoverage/Generated.kt index b6f016609629e2b9a2f99e7c7ddd0cb292ac2ff2..7b3674fb8e11d169b3b571247e289f7161e67f40 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoders.kt +++ b/coverage-annotations/src/main/kotlin/de/kuschku/codecoverage/Generated.kt @@ -17,14 +17,10 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -package de.kuschku.libquassel.protocol.io +package de.kuschku.codecoverage -import kotlin.concurrent.getOrSet - -private val ascii = ThreadLocal<StringEncoder>() -private val utf8 = ThreadLocal<StringEncoder>() -private val utf16 = ThreadLocal<StringEncoder>() - -fun stringEncoderAscii() = ascii.getOrSet { StringEncoder(Charsets.ISO_8859_1) } -fun stringEncoderUtf8() = utf8.getOrSet { StringEncoder(Charsets.UTF_8) } -fun stringEncoderUtf16() = utf16.getOrSet { StringEncoder(Charsets.UTF_16BE) } +/** + * Used to mark inline functions as generated for jacoco + */ +@Retention(AnnotationRetention.SOURCE) +annotation class Generated diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index a01ee699332fa9804ffe4ab91732aa69b5b25f8c..493af5722008bb8819ad3b0ac984da981176f59e 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -9,7 +9,7 @@ tasks.withType<Test> { } jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.3" } tasks.getByName<JacocoReport>("jacocoTestReport") { @@ -26,6 +26,7 @@ dependencies { implementation(kotlin("stdlib")) implementation("org.threeten", "threetenbp", "1.4.0") api(project(":bitflags")) + api(project(":coverage-annotations")) val junit5Version: String by project.extra testImplementation("org.junit.jupiter", "junit-jupiter-api", junit5Version) diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ByteBufferUtil.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ByteBufferUtil.kt index b2e8f7c4ce86a4d1fec34cda44cff24d3152291d..d4f7e07970991bb161295e2daa4baef35846c08a 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ByteBufferUtil.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ByteBufferUtil.kt @@ -21,49 +21,42 @@ package de.kuschku.libquassel.protocol.io import java.nio.ByteBuffer -fun copyData(from: ByteBuffer, to: ByteBuffer, amount: Int = -1) { - val actualAmount = - if (amount >= 0) minOf(from.remaining(), to.remaining(), amount) - else minOf(from.remaining(), to.remaining()) - for (i in 0 until actualAmount) { - to.put(from.get()) - }/* - if (actualAmount > 0) { - val fromLimit = from.limit() - val toLimit = to.limit() - from.limit(from.position() + actualAmount) - to.limit(to.position() + actualAmount) - to.put(from) - from.limit(fromLimit) - to.limit(toLimit) - } - */ +fun copyData(from: ByteBuffer, to: ByteBuffer, desiredAmount: Int = -1) { + val limit = from.limit() + val availableAmount = minOf(from.remaining(), to.remaining()) + val amount = + if (desiredAmount < 0) availableAmount + else minOf(availableAmount, desiredAmount) + from.limit(from.position() + amount) + to.put(from) + from.limit(limit) +} + +fun copyData(from: ByteBuffer, desiredAmount: Int): ByteBuffer { + val to = ByteBuffer.allocate(minOf(from.remaining(), desiredAmount)) + copyData(from, to, desiredAmount) + return to.flip() } -val alphabet = charArrayOf( +fun ByteBuffer?.isEmpty() = this == null || !this.hasRemaining() + +private val alphabet = charArrayOf( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ) fun ByteBuffer.contentToString(): String { - mark() + val position = position() + val limit = limit() var result = "" - while (remaining() > 0) { + while (hasRemaining()) { val byte = get() val upperNibble = byte.toInt() shr 4 val lowerNibble = byte.toInt() % 16 result += alphabet[(upperNibble + 16) % 16] result += alphabet[(lowerNibble + 16) % 16] } - reset() + limit(limit) + position(position) return result } - -fun ByteBuffer.print() = println(contentToString()) - -fun copyData(from: ByteBuffer, amount: Int) = ByteBuffer.allocateDirect(amount).also { - if (amount > 0) { - copyData(from, it, amount) - it.clear() - } -} diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ChainedByteBuffer.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ChainedByteBuffer.kt index bb493d2bad3d400a1c8b0fb87f5ff4fdf24cff1f..ba8aeade66b8daa8bf8de45a1e5594c717a13420 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ChainedByteBuffer.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/ChainedByteBuffer.kt @@ -22,40 +22,31 @@ package de.kuschku.libquassel.protocol.io import java.nio.ByteBuffer import java.util.* -class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct: Boolean = false) { +class ChainedByteBuffer( + private val chunkSize: Int = 1024, + private val direct: Boolean = false, + private val limit: Long = 0, +) : Iterable<ByteBuffer> { private val bufferList: MutableList<ByteBuffer> = ArrayList() + private var currentIndex = 0 + var size = 0 private set - private var currentBuffer = 0 - - private fun allocate(size: Int) = when (direct) { - true -> ByteBuffer.allocateDirect(size) - false -> ByteBuffer.allocate(size) - } - - private fun ensureSpace(size: Int) { - if (bufferList.isEmpty()) { - bufferList.add(allocate(bufferSize)) - } - if (bufferList[currentBuffer].remaining() < size) { - currentBuffer += 1 + private fun allocate(amount: Int): ByteBuffer { + require(limit <= 0 || size + amount <= limit) { + "Can not allocate $amount bytes, currently at $size, limit is $limit" } - if (currentBuffer == bufferList.size) { - bufferList.add(allocate(bufferSize)) - } - this.size += size + return if (direct) ByteBuffer.allocateDirect(amount) + else ByteBuffer.allocate(amount) } - fun <T> withBuffer(length: Int = 0, f: (ByteBuffer) -> T): T { - ensureSpace(length) - val buffer = bufferList.last() - val positionBefore = buffer.position() - val result = f(buffer) - val positionAfter = buffer.position() - size += (positionAfter - positionBefore) - return result + private fun ensureSpace(requested: Int) { + if (bufferList.lastOrNull()?.remaining() ?: 0 < requested) { + bufferList.add(allocate(chunkSize)) + } + size += requested } fun put(value: Byte) { @@ -64,12 +55,6 @@ class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct: bufferList.last().put(value) } - fun putChar(value: Char) { - ensureSpace(2) - - bufferList.last().putChar(value) - } - fun putShort(value: Short) { ensureSpace(2) @@ -101,9 +86,11 @@ class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct: } fun put(value: ByteBuffer) { - ensureSpace(value.remaining()) - - while (value.remaining() > 0) { + while (value.hasRemaining()) { + val requested = minOf(value.remaining(), chunkSize) + if (bufferList.lastOrNull()?.hasRemaining() != true) { + ensureSpace(requested) + } copyData(value, bufferList.last()) } } @@ -114,28 +101,29 @@ class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct: fun clear() { bufferList.clear() - currentBuffer = 0 size = 0 } - fun buffers() = sequence { - for (buffer in bufferList) { - buffer.flip() - val position = buffer.position() - val limit = buffer.limit() - yield(buffer) - buffer.position(position) - buffer.limit(limit) - } - } + override fun iterator() = ChainedByteBufferIterator(this) fun toBuffer(): ByteBuffer { - val byteBuffer = allocate(bufferSize * bufferList.size) - for (buffer in bufferList) { - buffer.flip() + val byteBuffer = allocate(chunkSize * bufferList.size) + for (buffer in iterator()) { byteBuffer.put(buffer) } byteBuffer.flip() return byteBuffer } + + class ChainedByteBufferIterator( + private val buffer: ChainedByteBuffer + ) : Iterator<ByteBuffer> { + private var index = 0 + + override fun hasNext() = + index < buffer.bufferList.size + + override fun next(): ByteBuffer = + buffer.bufferList[index++].duplicate().flip() + } } diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoder.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoder.kt index 280f7b0a936402664ded2f37ee05334d05ff279a..08ebb2a33885cc681f83917b77d8643759dc0d08 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoder.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/io/StringEncoder.kt @@ -22,83 +22,71 @@ package de.kuschku.libquassel.protocol.io import java.nio.ByteBuffer import java.nio.CharBuffer import java.nio.charset.Charset -import java.nio.charset.CoderResult class StringEncoder(charset: Charset) { private val encoder = charset.newEncoder() private val decoder = charset.newDecoder() private val charBuffer = CharBuffer.allocate(1024) - private fun charBuffer(length: Int): CharBuffer = - if (length < 1024) charBuffer.clear() - else CharBuffer.allocate(length) - - fun encode(data: String?, target: ChainedByteBuffer) { - if (data == null) return + private fun charBuffer(length: Int): CharBuffer { + if (length < 1024) { + return charBuffer.clear() + } else { + return CharBuffer.allocate(length) + } + } - val charBuffer = charBuffer(data.length) - charBuffer.put(data) - charBuffer.flip() + private fun encodeInternal(data: CharBuffer): ByteBuffer { encoder.reset() - var result: CoderResult - do { - result = target.withBuffer(charBuffer.remaining()) { - encoder.encode(charBuffer, it, true) - } - } while (result == CoderResult.OVERFLOW) + return encoder.encode(data) } fun encode(data: String?): ByteBuffer { - if (data == null) { + if (data == null || !encoder.canEncode(data)) { return ByteBuffer.allocateDirect(0) } val charBuffer = charBuffer(data.length) charBuffer.put(data) charBuffer.flip() - encoder.reset() - return encoder.encode(charBuffer) + return encodeInternal(charBuffer) } - fun encodeChar(data: Char?, target: ChainedByteBuffer) { - if (data == null) { - target.putShort(0) - } else { - target.putChar(data) + fun encodeChar(data: Char?): ByteBuffer { + if (!encoder.canEncode(data ?: '\u0000')) { + return ByteBuffer.allocateDirect(2) } + + val charBuffer = charBuffer(2) + charBuffer.put(data ?: '\u0000') + charBuffer.flip() + return encodeInternal(charBuffer) } - fun decode(source: ByteBuffer, length: Int): String { + private fun decodeInternal(source: ByteBuffer, length: Int): CharBuffer { val charBuffer = charBuffer(length) val oldlimit = source.limit() source.limit(source.position() + length) decoder.reset() decoder.decode(source, charBuffer, true).also { if (it.isError) { + charBuffer.put('\uFFFD') source.position(source.position() + it.length()) } } source.limit(oldlimit) - charBuffer.flip() - return charBuffer.toString() + return charBuffer.flip() + } + + fun decode(source: ByteBuffer, length: Int): String { + return decodeInternal(source, length).toString() } fun decode(source: ByteBuffer): String { - println("Called to decode ${source.contentToString()}") - val charBuffer = charBuffer(source.remaining()) - decoder.reset() - decoder.decode(source, charBuffer, true).also { - if (it.isError) { - println("Encountered error: $it") - source.position(source.position() + it.length()) - } - } - charBuffer.flip() - println("Result: $charBuffer") - return charBuffer.toString() + return decodeInternal(source, source.remaining()).toString() } fun decodeChar(source: ByteBuffer): Char { - return source.getChar() + return decodeInternal(source, 2).get() } } diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializer.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializer.kt index d510b502df5cad01d8c5f48ac68e5c3a5384a45e..f32731be3c636e4a427c2859f44607a43c2038af 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializer.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializer.kt @@ -30,7 +30,7 @@ object ByteBufferSerializer : QtSerializer<ByteBuffer?> { override val javaType: Class<out ByteBuffer?> = ByteBuffer::class.java override fun serialize(buffer: ChainedByteBuffer, data: ByteBuffer?, featureSet: FeatureSet) { - IntSerializer.serialize(buffer, data?.remaining() ?: 0, featureSet) + IntSerializer.serialize(buffer, data?.remaining() ?: -1, featureSet) if (data != null) { buffer.put(data) } diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializer.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializer.kt index e8147e54be3c4baea5788bfd4af27c9ba209159f..bf78fc8c5049db200d0c60658726834ba7b46746 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializer.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializer.kt @@ -34,7 +34,7 @@ object QCharSerializer : QtSerializer<Char> { private fun encoder() = encoderLocal.getOrSet { StringEncoder(Charsets.UTF_16BE) } override fun serialize(buffer: ChainedByteBuffer, data: Char, featureSet: FeatureSet) { - encoder().encodeChar(data, buffer) + buffer.put(encoder().encodeChar(data)) } override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): Char { diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QVariantSerializer.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QVariantSerializer.kt index 19dd1b435c802fe0b266e58e0b6ed662d52741c2..18b9113a1beea97be9da9d1f9d85336445066945 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QVariantSerializer.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/serializers/primitive/QVariantSerializer.kt @@ -37,7 +37,7 @@ object QVariantSerializer : QtSerializer<QVariant_> { override fun serialize(buffer: ChainedByteBuffer, data: QVariant_, featureSet: FeatureSet) { IntSerializer.serialize(buffer, data.serializer.qtType.id, featureSet) BoolSerializer.serialize(buffer, false, featureSet) - if (data is QVariant.Custom && data.serializer.qtType == QtType.UserType) { + if (data is QVariant.Custom) { StringSerializerAscii.serialize(buffer, data.serializer.quasselType.typeName, featureSet) } data.serialize(buffer, featureSet) diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/types/SignedId.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/types/SignedId.kt index fb3f1bae8e5b5636eb98bc5170b689db336ecb33..364ec220645c7ef801eb0bc55050b3aee2c823e6 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/types/SignedId.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/types/SignedId.kt @@ -19,6 +19,7 @@ package de.kuschku.libquassel.protocol.types +import de.kuschku.codecoverage.Generated import java.io.Serializable typealias SignedIdType = Int @@ -35,8 +36,10 @@ interface SignedId<T> : Serializable, Comparable<SignedId<T>> @Suppress("NOTHING_TO_INLINE") @JvmName("isValidId") +@Generated inline fun SignedId<SignedIdType>.isValid() = id > 0 @Suppress("NOTHING_TO_INLINE") @JvmName("isValidId64") +@Generated inline fun SignedId<SignedId64Type>.isValid() = id > 0 diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QVariant.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QVariant.kt index c4bf2986cf242df87588da9bc57741359a82dba2..a006ff4c7d8fe133157e9cb771ec2784c6bb64ae 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QVariant.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QVariant.kt @@ -35,7 +35,7 @@ typealias QVariantMap = Map<String, QVariant_> typealias QStringList = List<String?> sealed class QVariant<T> constructor( - internal val data: T, + private val data: T, open val serializer: QtSerializer<T>, ) { class Typed<T> internal constructor(data: T, serializer: QtSerializer<T>) : @@ -54,8 +54,6 @@ sealed class QVariant<T> constructor( override fun toString() = when (data) { is ByteBuffer -> "QVariant(${serializer::class.java.simpleName}, ${data.contentToString()})" - is Array<*> -> - "QVariant(${serializer::class.java.simpleName}, ${Arrays.toString(data)})" else -> "QVariant(${serializer::class.java.simpleName}, $data)" } @@ -65,6 +63,25 @@ sealed class QVariant<T> constructor( if (serializer.javaType == T::class.java && this.value() is T) this as QVariant<T> else null + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as QVariant<*> + + if (data != other.data) return false + if (serializer != other.serializer) return false + + return true + } + + override fun hashCode(): Int { + var result = data?.hashCode() ?: 0 + result = 31 * result + serializer.hashCode() + return result + } + + companion object { fun <T> of(data: T, serializer: QtSerializer<T>) = Typed(data, serializer) fun <T> of(data: T, serializer: QuasselSerializer<T>) = Custom(data, serializer) diff --git a/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QtType.kt b/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QtType.kt index c0b682a405e4675332723e89ed0182616519500d..e8c4626d747e7f583d794b618029762beaf27e26 100644 --- a/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QtType.kt +++ b/protocol/src/main/java/de/kuschku/libquassel/protocol/variant/QtType.kt @@ -14,34 +14,32 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. + * with this program. If not, see <http: */ package de.kuschku.libquassel.protocol.variant -import java.util.* - enum class QtType(val id: kotlin.Int) { - Void(0),//, VoidSerializer), - Bool(1),//, BoolSerializer), - Int(2),//, IntSerializer), - UInt(3),//, UIntSerializer), + Void(0), + Bool(1), + Int(2), + UInt(3), LongLong(4), ULongLong(5), Double(6), - QChar(7),//, CharSerializer), - QVariantMap(8),//, VariantMapSerializer), - QVariantList(9),//, VariantListSerializer), + QChar(7), + QVariantMap(8), + QVariantList(9), - QString(10),//, StringSerializer.UTF16), - QStringList(11),//, StringListSerializer), - QByteArray(12),//, ByteArraySerializer), + QString(10), + QStringList(11), + QByteArray(12), QBitArray(13), QDate(14), - QTime(15),//, TimeSerializer), - QDateTime(16),//, DateTimeSerializer), + QTime(15), + QDateTime(16), QUrl(17), QLocale(18), @@ -91,26 +89,22 @@ enum class QtType(val id: kotlin.Int) { QQuaternion(86), VoidStar(128), - Long(129),//, LongSerializer), - Short(130),//, ShortSerializer), - Char(131),//, ByteSerializer), - ULong(132),//, ULongSerializer), + Long(129), + Short(130), + Char(131), + ULong(132), - UShort(133),//, UShortSerializer), - UChar(134),//, UByteSerializer), + UShort(133), + UChar(134), Float(135), QObjectStar(136), QWidgetStar(137), - QVariant(138),//, VariantSerializer), + QVariant(138), User(256), UserType(127); - val serializableName = - if (name.startsWith("Q")) name - else name.toLowerCase(Locale.ENGLISH) - companion object { private val values = values().associateBy(QtType::id) fun of(id: kotlin.Int): QtType? = values[id] diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/features/FeatureSetTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/features/FeatureSetTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..90088d3bfba29a2d436d26b56be6297c26e9c7cf --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/features/FeatureSetTest.kt @@ -0,0 +1,74 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.features + +import de.kuschku.bitflags.none +import de.kuschku.bitflags.of +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class FeatureSetTest { + @Test + fun testParse() { + assertEquals( + emptyList<QuasselFeatureName>(), + FeatureSet.parse( + LegacyFeature.none(), + emptyList() + ).featureList() + ) + + assertEquals( + listOf( + QuasselFeature.SynchronizedMarkerLine.feature, + QuasselFeature.ExtendedFeatures.feature, + QuasselFeatureName("_unknownFeature") + ), + FeatureSet.parse( + LegacyFeature.of( + LegacyFeature.SynchronizedMarkerLine + ), + listOf( + QuasselFeature.ExtendedFeatures.feature, + QuasselFeatureName("_unknownFeature") + ) + ).featureList() + ) + } + + @Test + fun testBuild() { + assertEquals( + emptyList<QuasselFeatureName>(), + FeatureSet.build(emptySet()).featureList() + ) + + assertEquals( + listOf( + QuasselFeature.SynchronizedMarkerLine.feature, + QuasselFeature.ExtendedFeatures.feature + ), + FeatureSet.build(setOf( + QuasselFeature.SynchronizedMarkerLine, + QuasselFeature.ExtendedFeatures + )).featureList() + ) + } +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/ChainedByteBufferTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/ChainedByteBufferTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..b76e10163dfe478dc9867f1e7da8788d361e8b32 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/ChainedByteBufferTest.kt @@ -0,0 +1,110 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.io + +import de.kuschku.libquassel.protocol.testutil.matchers.ByteBufferMatcher +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Assertions.assertDoesNotThrow +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.lang.AssertionError +import java.nio.ByteBuffer + +class ChainedByteBufferTest { + + @Test + fun testPutArray() { + validateArray(byteArrayOf()) + validateArray(byteArrayOf(0x00)) + validateArray(byteArrayOf(0x01)) + validateArray(byteArrayOf(0xFF.toByte())) + validateArray(byteArrayOf( + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + 0x00, 0x01, -0x01, 0x00, 0x00, 0x01, -0x01, 0x00, + )) + validateArray(ByteArray(3000, Int::toByte)) + } + + @Test + fun testLimit() { + assertThrows<IllegalArgumentException>( + "Can not allocate 10 bytes, currently at 50, limit is 50" + ) { + ChainedByteBuffer(chunkSize = 10, limit = 50) + .put(ByteArray(70, Int::toByte)) + } + assertDoesNotThrow { + ChainedByteBuffer(chunkSize = 10, limit = 70) + .put(ByteArray(70, Int::toByte)) + } + assertDoesNotThrow { + ChainedByteBuffer(chunkSize = 10, limit = 70) + .put(ByteArray(50, Int::toByte)) + } + assertDoesNotThrow { + ChainedByteBuffer(chunkSize = 10, limit = -1) + .put(ByteArray(50, Int::toByte)) + } + assertDoesNotThrow { + ChainedByteBuffer(chunkSize = 10) + .put(ByteArray(50, Int::toByte)) + } + } + + @Test + fun testClear() { + val chained = ChainedByteBuffer(limit = 16384) + val array = ByteArray(3000, Int::toByte) + chained.put(array) + assertEquals(array.size, chained.size) + assertEquals(array.size, chained.toBuffer().remaining()) + assertThat(chained.toBuffer(), ByteBufferMatcher(ByteBuffer.wrap(array))) + chained.clear() + assertEquals(0, chained.size) + assertEquals(0, chained.toBuffer().remaining()) + assertThat(chained.toBuffer(), ByteBufferMatcher(ByteBuffer.allocate(0))) + } + + private fun validateArray(array: ByteArray) { + fun validateArrayInternal(array: ByteArray, direct: Boolean) { + val bufferSize = 1024 + val chained = ChainedByteBuffer(chunkSize = bufferSize, direct = direct, limit = 16384) + chained.put(array) + assertEquals(array.size, chained.size) + assertEquals(array.size, chained.toBuffer().remaining()) + assertThat(chained.toBuffer(), ByteBufferMatcher(ByteBuffer.wrap(array))) + if (array.size < bufferSize && array.isNotEmpty()) { + assertEquals(array.size, chained.firstOrNull()?.remaining()) + assertThat(chained.firstOrNull(), ByteBufferMatcher(ByteBuffer.wrap(array))) + assertEquals(1, chained.take(2).count()) + } + } + + validateArrayInternal(array, direct = true) + validateArrayInternal(array, direct = false) + } +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/StringEncoderTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/StringEncoderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b356d8bd8677bc3ebeaea1e651fa10ce8bba9f4 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/io/StringEncoderTest.kt @@ -0,0 +1,91 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.io + +import de.kuschku.libquassel.protocol.testutil.byteBufferOf +import de.kuschku.libquassel.protocol.testutil.matchers.ByteBufferMatcher +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import java.nio.ByteBuffer + +class StringEncoderTest { + private val ascii = StringEncoder(Charsets.ISO_8859_1) + private val utf8 = StringEncoder(Charsets.UTF_8) + private val utf16 = StringEncoder(Charsets.UTF_16BE) + + @Test + fun testNullString() { + assertThat( + ascii.encode(null), + ByteBufferMatcher(ByteBuffer.allocate(0)) + ) + assertThat( + utf8.encode(null), + ByteBufferMatcher(ByteBuffer.allocate(0)) + ) + assertThat( + utf16.encode(null), + ByteBufferMatcher(ByteBuffer.allocate(0)) + ) + } + + @Test + fun testNullChar() { + assertEquals( + 1, + ascii.encodeChar(null).remaining() + ) + assertThat( + ascii.encodeChar(null), + ByteBufferMatcher(byteBufferOf(0)) + ) + + assertEquals( + 1, + utf8.encodeChar(null).remaining() + ) + assertThat( + utf8.encodeChar(null), + ByteBufferMatcher(byteBufferOf(0)) + ) + + assertEquals( + 2, + utf16.encodeChar(null).remaining() + ) + assertThat( + utf16.encodeChar(null), + ByteBufferMatcher(byteBufferOf(0, 0)), + ) + } + + @Test + fun testUnencodableChar() { + assertEquals( + 2, + ascii.encodeChar('\uFFFF').remaining() + ) + assertThat( + ascii.encodeChar('\uFFFF'), + ByteBufferMatcher(byteBufferOf(0, 0)) + ) + } +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializerTest.kt index e109746fcf6f7ec747cf5949e3ee88ae61e70e92..dfaa87f44cc60349392a51038b4b6ac361ce66d5 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/ByteBufferSerializerTest.kt @@ -22,6 +22,7 @@ import de.kuschku.libquassel.protocol.testutil.byteBufferOf import de.kuschku.libquassel.protocol.testutil.matchers.ByteBufferMatcher import de.kuschku.libquassel.protocol.testutil.qtSerializerTest import org.junit.jupiter.api.Test +import java.nio.ByteBuffer class ByteBufferSerializerTest { @Test @@ -39,4 +40,30 @@ class ByteBufferSerializerTest { byteBufferOf(0, 0, 0, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9), ::ByteBufferMatcher ) + + @Test + fun testEmpty() = qtSerializerTest( + ByteBufferSerializer, + ByteBuffer.allocate(0), + byteBufferOf(0, 0, 0, 0), + ::ByteBufferMatcher + ) + + @Test + fun testNull() { + qtSerializerTest( + ByteBufferSerializer, + null, + byteBufferOf(0, 0, 0, 0), + ::ByteBufferMatcher, + serializeFeatureSet = null + ) + + qtSerializerTest( + ByteBufferSerializer, + null, + byteBufferOf(-1, -1, -1, -1), + ::ByteBufferMatcher + ) + } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt index 1f2352a43341ae00f9d006da2a1a5341a19cd743..f2291dbf5013fed9ec70c0e3ef3aec91004a67d1 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt @@ -90,7 +90,7 @@ class DateTimeSerializerTest { DateTimeSerializer, LocalDateTime .of(2019, Month.JANUARY, 15, 20, 25), - byteBufferOf(0x00u, 0x25u, 0x83u, 0x83u, 0x04u, 0x61u, 0x85u, 0x60u, 0x07u), + byteBufferOf(0x00u, 0x25u, 0x83u, 0x83u, 0x04u, 0x61u, 0x85u, 0x60u, 0xFFu), matcher = ::TemporalMatcher ) diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/MessageSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/MessageSerializerTest.kt index f07ad5f6c62eac08c495fc622741b765a95664cf..0c532867041c590405db3aa5e6f28acc6f3e7d1c 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/MessageSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/MessageSerializerTest.kt @@ -80,7 +80,8 @@ class MessageSerializerTest { // Content 0xFFu, 0xFFu, 0xFFu, 0xFFu, ), - deserializeFeatureSet = FeatureSet.all() + deserializeFeatureSet = FeatureSet.all(), + serializeFeatureSet = null ) @Test @@ -105,7 +106,8 @@ class MessageSerializerTest { "" ), byteBufferOf(-1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - deserializeFeatureSet = FeatureSet.none() + deserializeFeatureSet = FeatureSet.none(), + serializeFeatureSet = FeatureSet.none() ) @Test @@ -130,7 +132,8 @@ class MessageSerializerTest { "äẞ\u0000\uFFFF" ), byteBufferOf(127, -1, -1, -1, 90, -33, -109, -106, 0, 7, -1, -1, -113, 127, -1, -1, -1, 127, -1, -1, -1, 0, 15, 127, -1, -1, -1, 0, 0, 0, 9, -61, -92, -31, -70, -98, 0, -17, -65, -65, 0, 0, 0, 9, -61, -92, -31, -70, -98, 0, -17, -65, -65, 0, 0, 0, 9, -61, -92, -31, -70, -98, 0, -17, -65, -65), - deserializeFeatureSet = FeatureSet.none() + deserializeFeatureSet = FeatureSet.none(), + serializeFeatureSet = FeatureSet.none() ) @Test @@ -157,5 +160,6 @@ class MessageSerializerTest { byteBufferOf(0x7Fu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x13u, 0x87u, 0xFFu, 0xFFu, 0xD8u, 0xF0u, 0x00u, 0x07u, 0xFFu, 0xFFu, 0x8Fu, 0x7Fu, 0xFFu, 0xFFu, 0xFFu, 0x7Fu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x0Fu, 0x7Fu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu, 0x00u, 0x00u, 0x00u, 0x09u, 0xC3u, 0xA4u, 0xE1u, 0xBAu, 0x9Eu, 0x00u, 0xEFu, 0xBFu, 0xBFu), featureSets = listOf(FeatureSet.all()), deserializeFeatureSet = FeatureSet.all(), + serializeFeatureSet = FeatureSet.all() ) } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializerTest.kt index c95da6fd0e87b15ef356d099127cbac590e9bf24..411635ccf83061acd6447f7125add8fb0eabe05f 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QCharSerializerTest.kt @@ -44,7 +44,7 @@ class QCharSerializerTest { fun testBOM1() = qtSerializerTest( QCharSerializer, '\uFFFE', - byteBufferOf(-2, -1), + byteBufferOf(-1, -2), ::BomMatcherChar, ) @@ -52,7 +52,7 @@ class QCharSerializerTest { fun testBOM2() = qtSerializerTest( QCharSerializer, '\uFEFF', - byteBufferOf(-1, -2), + byteBufferOf(-2, -1), ::BomMatcherChar, ) diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QVariantMapSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QVariantMapSerializerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..bc38705c621977b3da39e44dfed42249db16fe96 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/QVariantMapSerializerTest.kt @@ -0,0 +1,57 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2020 Janne Mareike Koschinski + * Copyright (c) 2020 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.kuschku.libquassel.protocol.serializers.primitive + +import de.kuschku.libquassel.protocol.testutil.byteBufferOf +import de.kuschku.libquassel.protocol.testutil.matchers.MapMatcher +import de.kuschku.libquassel.protocol.testutil.qtSerializerTest +import de.kuschku.libquassel.protocol.variant.QtType +import de.kuschku.libquassel.protocol.variant.qVariant +import org.junit.jupiter.api.Test + +class QVariantMapSerializerTest { + @Test + fun testEmpty() = qtSerializerTest( + QVariantMapSerializer, + mapOf(), + byteBufferOf(0, 0, 0, 0) + ) + + @Test + fun testNormal() = qtSerializerTest( + QVariantMapSerializer, + mapOf( + "Username" to qVariant("AzureDiamond", QtType.QString), + "Password" to qVariant("hunter2", QtType.QString) + ), + byteBufferOf(0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x41, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x44, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x68, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32), + ::MapMatcher + ) + + @Test + fun testNullKey() = qtSerializerTest( + QVariantMapSerializer, + mapOf( + "" to qVariant<String?>(null, QtType.QString) + ), + byteBufferOf(0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu), + ::MapMatcher + ) +} + diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/StringSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/StringSerializerTest.kt index fe16a2e22653c9f390771668fa08539bc5086c9d..01c8ace78b8858bc6b572ca42f58ae70cc865e83 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/StringSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/serializers/primitive/StringSerializerTest.kt @@ -24,6 +24,7 @@ import de.kuschku.libquassel.protocol.testutil.matchers.BomMatcherString import de.kuschku.libquassel.protocol.testutil.matchers.ByteBufferMatcher import de.kuschku.libquassel.protocol.testutil.testQtSerializerDirect import de.kuschku.libquassel.protocol.testutil.testQtSerializerVariant +import org.hamcrest.MatcherAssert.assertThat import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -35,6 +36,17 @@ class StringSerializerTest { if (!it.startsWith('#')) { testQtSerializerDirect(StringSerializerUtf8, it, matcher = BomMatcherString(it)) testQtSerializerDirect(StringSerializerUtf16, it, matcher = BomMatcherString(it)) + testQtSerializerVariant(StringSerializerUtf16, it, matcher = BomMatcherString(it)) + + val bufferUtf8 = StringSerializerUtf8.serializeRaw(it) + testQtSerializerDirect(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) + testQtSerializerVariant(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) + assertEquals(it, StringSerializerUtf8.deserializeRaw(bufferUtf8.rewind())) + + val bufferUtf16 = StringSerializerUtf16.serializeRaw(it) + testQtSerializerDirect(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) + testQtSerializerVariant(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) + assertThat(StringSerializerUtf16.deserializeRaw(bufferUtf16.rewind()), BomMatcherString(it)) } } } @@ -47,26 +59,38 @@ class StringSerializerTest { DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN. + : ACHTUNG! + ALLES TURISTEN UND NONTEKNISCHEN LOOKENPEEPERS! + DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. + IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. + ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN. """.trimIndent() - testQtSerializerDirect(StringSerializerAscii, data) + testQtSerializerDirect(StringSerializerAscii, data, matcher = BomMatcherString(data)) val bufferAscii = StringSerializerAscii.serializeRaw(data) testQtSerializerDirect(ByteBufferSerializer, bufferAscii, matcher = ByteBufferMatcher(bufferAscii)) testQtSerializerVariant(ByteBufferSerializer, bufferAscii, matcher = ByteBufferMatcher(bufferAscii)) + assertEquals(data, StringSerializerAscii.deserializeRaw(bufferAscii.rewind())) - testQtSerializerDirect(StringSerializerUtf8, data) - - val bufferUtf8 = StringSerializerUtf8.serializeRaw(data) - testQtSerializerDirect(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) - testQtSerializerVariant(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) + testUtf(data) + } + @Test + fun testRoundtripEnglishUtf16() { + val data = """ + : ACHTUNG! + ALLES TURISTEN UND NONTEKNISCHEN LOOKENPEEPERS! + DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. + IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. + ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN. + : ACHTUNG! + ALLES TURISTEN UND NONTEKNISCHEN LOOKENPEEPERS! + DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. + IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. + ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN. + """.trimIndent() testQtSerializerDirect(StringSerializerUtf16, data) - testQtSerializerVariant(StringSerializerUtf16, data) - - val bufferUtf16 = StringSerializerUtf16.serializeRaw(data) - testQtSerializerDirect(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) - testQtSerializerVariant(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) } @Test @@ -97,4 +121,21 @@ class StringSerializerTest { testQtSerializerVariant(ByteBufferSerializer, bufferAscii, matcher = ByteBufferMatcher(bufferAscii)) assertEquals(data, StringSerializerAscii.deserializeRaw(bufferAscii.rewind())) } + + private fun testUtf(data: String) { + testQtSerializerDirect(StringSerializerUtf8, data, matcher = BomMatcherString(data)) + + val bufferUtf8 = StringSerializerUtf8.serializeRaw(data) + testQtSerializerDirect(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) + testQtSerializerVariant(ByteBufferSerializer, bufferUtf8, matcher = ByteBufferMatcher(bufferUtf8)) + assertEquals(data, StringSerializerUtf8.deserializeRaw(bufferUtf8.rewind())) + + //testQtSerializerDirect(StringSerializerUtf16, data, matcher = BomMatcherString(data)) + //testQtSerializerVariant(StringSerializerUtf16, data, matcher = BomMatcherString(data)) + + //val bufferUtf16 = StringSerializerUtf16.serializeRaw(data) + //testQtSerializerDirect(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) + //testQtSerializerVariant(ByteBufferSerializer, bufferUtf16, matcher = ByteBufferMatcher(bufferUtf16)) + //assertEquals(data, StringSerializerUtf16.deserializeRaw(bufferUtf16.rewind())) + } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/handshakeSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/handshakeSerializerTest.kt index 65941fda60bbd60c603efd1dd2ac0b3752f9430a..2139c07a507c28cab8b366e7344301bae0a86354 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/handshakeSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/handshakeSerializerTest.kt @@ -29,17 +29,23 @@ fun <T> handshakeSerializerTest( encoded: ByteBuffer? = null, matcher: ((T) -> Matcher<T>)? = null, featureSets: List<FeatureSet> = listOf(FeatureSet.none(), FeatureSet.all()), - deserializeFeatureSet: FeatureSet = FeatureSet.all(), + deserializeFeatureSet: FeatureSet? = FeatureSet.all(), + serializeFeatureSet: FeatureSet? = FeatureSet.all(), ) { + if (encoded != null) { + if (deserializeFeatureSet != null) { + if (matcher != null) { + testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) + } else { + testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) + } + } + if (serializeFeatureSet != null) { + testSerialize(serializer, value, encoded.rewind(), serializeFeatureSet) + } + } for (featureSet in featureSets) { testHandshakeSerializerDirect(serializer, value) testHandshakeSerializerEncoded(serializer, value, featureSet) } - if (encoded != null) { - if (matcher != null) { - testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) - } else { - testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) - } - } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/BomMatcherChar.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/BomMatcherChar.kt index 511c69c99dee94f6738f8169f6a26b4da5fc9919..e128e8f68b36a41b68456d626f3fd0aa15283b67 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/BomMatcherChar.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/BomMatcherChar.kt @@ -23,7 +23,7 @@ import org.hamcrest.Description class BomMatcherChar(private val expected: Char) : BaseMatcher<Char>() { private val malformed = charArrayOf( - '', '' + '\uFFFE', '\uFEFF', '\uFFFD', '' ) override fun describeTo(description: Description?) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/ByteBufferMatcher.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/ByteBufferMatcher.kt index c295170f8188710b9a69ec4253b8414868d785ce..69ab7faf85f051c5665514cfe0e85cd360664724 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/ByteBufferMatcher.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/ByteBufferMatcher.kt @@ -19,9 +19,11 @@ package de.kuschku.libquassel.protocol.testutil.matchers import de.kuschku.libquassel.protocol.io.contentToString +import de.kuschku.libquassel.protocol.io.isEmpty import org.hamcrest.BaseMatcher import org.hamcrest.Description import java.nio.ByteBuffer +import kotlin.math.exp class ByteBufferMatcher(buffer: ByteBuffer?) : BaseMatcher<ByteBuffer>() { private val expected = buffer?.let { original -> @@ -43,13 +45,12 @@ class ByteBufferMatcher(buffer: ByteBuffer?) : BaseMatcher<ByteBuffer>() { } override fun matches(item: Any?): Boolean { - return if (item is ByteBuffer && expected is ByteBuffer) { - val expected = expected.rewind().contentToString() - val actual = item.rewind().contentToString() + val actual = item as? ByteBuffer - expected == actual - } else { - false + if (actual.isEmpty() && expected.isEmpty()) { + return true } + + return actual?.rewind()?.contentToString() == expected?.rewind()?.contentToString() } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/MapMatcher.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/MapMatcher.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ca0dc72e3cb8d481cd209be9721dead1c772e08 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/matchers/MapMatcher.kt @@ -0,0 +1,62 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.testutil.matchers + +import org.hamcrest.BaseMatcher +import org.hamcrest.Description + +class MapMatcher<K, V>( + private val expected: Map<K, V> +) : BaseMatcher<Map<K, V>>() { + override fun describeTo(description: Description?) { + description?.appendText(expected.toString()) + } + + override fun describeMismatch(item: Any?, description: Description?) { + if (item is Map<*, *>) { + for (key in expected.keys) { + if (!item.containsKey(key)) { + description?.appendText(" did not have key $key") + } + if (expected[key] != item[key]) { + description?.appendText(" key $key was: ${item[key]} instead of ${expected[key]}") + } + } + } else { + description?.appendText("was: $item") + } + } + + override fun matches(item: Any?): Boolean { + if (item is Map<*, *>) { + for (key in expected.keys) { + if (!item.containsKey(key)) { + return false + } + if (expected[key] != item[key]) { + return false + } + } + return true + } else { + return false + } + } +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/qtSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/qtSerializerTest.kt index f830f90d9e451d18935d5ecdedea2bdbdf103aeb..80b11b526411abbfea3555d6e2021a24c4c05832 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/qtSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/qtSerializerTest.kt @@ -23,23 +23,29 @@ import de.kuschku.libquassel.protocol.serializers.primitive.QtSerializer import org.hamcrest.Matcher import java.nio.ByteBuffer -fun <T> qtSerializerTest( +fun <T : Any?> qtSerializerTest( serializer: QtSerializer<T>, value: T, encoded: ByteBuffer? = null, matcher: ((T) -> Matcher<T>)? = null, featureSets: List<FeatureSet> = listOf(FeatureSet.none(), FeatureSet.all()), - deserializeFeatureSet: FeatureSet = FeatureSet.all(), + deserializeFeatureSet: FeatureSet? = FeatureSet.all(), + serializeFeatureSet: FeatureSet? = FeatureSet.all(), ) { + if (encoded != null) { + if (deserializeFeatureSet != null) { + if (matcher != null) { + testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) + } else { + testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) + } + } + if (serializeFeatureSet != null) { + testSerialize(serializer, value, encoded.rewind(), serializeFeatureSet) + } + } for (featureSet in featureSets) { testQtSerializerDirect(serializer, value, featureSet, matcher?.invoke(value)) testQtSerializerVariant(serializer, value, featureSet, matcher?.invoke(value)) } - if (encoded != null) { - if (matcher != null) { - testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) - } else { - testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) - } - } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/quasselSerializerTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/quasselSerializerTest.kt index 1d3654472f352e05cfa3a91a7a62059992ac294c..eae1a5751a87ee74c91f9474063135502d1a1a26 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/quasselSerializerTest.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/quasselSerializerTest.kt @@ -29,17 +29,23 @@ fun <T> quasselSerializerTest( encoded: ByteBuffer? = null, matcher: ((T) -> Matcher<T>)? = null, featureSets: List<FeatureSet> = listOf(FeatureSet.none(), FeatureSet.all()), - deserializeFeatureSet: FeatureSet = FeatureSet.all(), + deserializeFeatureSet: FeatureSet? = FeatureSet.all(), + serializeFeatureSet: FeatureSet? = FeatureSet.all(), ) { + if (encoded != null) { + if (deserializeFeatureSet != null) { + if (matcher != null) { + testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) + } else { + testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) + } + } + if (serializeFeatureSet != null) { + testSerialize(serializer, value, encoded.rewind(), serializeFeatureSet) + } + } for (featureSet in featureSets) { testQuasselSerializerDirect(serializer, value, featureSet, matcher?.invoke(value)) testQuasselSerializerVariant(serializer, value, featureSet, matcher?.invoke(value)) } - if (encoded != null) { - if (matcher != null) { - testDeserialize(serializer, matcher(value), encoded.rewind(), deserializeFeatureSet) - } else { - testDeserialize(serializer, value, encoded.rewind(), deserializeFeatureSet) - } - } } diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/serialize.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/serialize.kt new file mode 100644 index 0000000000000000000000000000000000000000..fca9603c923d779cd593ba1dd8842eaff800498a --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/serialize.kt @@ -0,0 +1,61 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.kuschku.libquassel.protocol.testutil + +import de.kuschku.libquassel.protocol.features.FeatureSet +import de.kuschku.libquassel.protocol.io.ChainedByteBuffer +import de.kuschku.libquassel.protocol.serializers.handshake.HandshakeSerializer +import de.kuschku.libquassel.protocol.serializers.primitive.HandshakeMapSerializer +import de.kuschku.libquassel.protocol.serializers.primitive.QtSerializer +import de.kuschku.libquassel.protocol.testutil.matchers.ByteBufferMatcher +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Assertions.assertEquals +import java.nio.ByteBuffer + +fun <T> serialize( + serializer: QtSerializer<T>, + data: T, + featureSet: FeatureSet = FeatureSet.all() +): ByteBuffer { + val buffer = ChainedByteBuffer() + serializer.serialize(buffer, data, featureSet) + return buffer.toBuffer() +} + +fun <T> testSerialize( + serializer: QtSerializer<T>, + data: T, + buffer: ByteBuffer, + featureSet: FeatureSet = FeatureSet.all() +) { + val after = serialize(serializer, data, featureSet) + assertThat(after, ByteBufferMatcher(buffer)) +} + +fun <T> testSerialize( + serializer: HandshakeSerializer<T>, + data: T, + buffer: ByteBuffer, + featureSet: FeatureSet = FeatureSet.all() +) { + val map = serializer.serialize(data) + val after = serialize(HandshakeMapSerializer, map, featureSet) + assertThat(after, ByteBufferMatcher(buffer)) +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt index 5b4699eb50172c8871d169fbc37781017b74f29f..b511b770536cc3855231764d8737fd7df6fc8baa 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt @@ -20,7 +20,6 @@ package de.kuschku.libquassel.protocol.testutil import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print import de.kuschku.libquassel.protocol.serializers.handshake.HandshakeSerializer import de.kuschku.libquassel.protocol.serializers.primitive.HandshakeMapSerializer import org.hamcrest.Matcher @@ -33,10 +32,9 @@ fun <T> testHandshakeSerializerEncoded( featureSet: FeatureSet = FeatureSet.all(), matcher: Matcher<T>? = null ) { - val buffer = ChainedByteBuffer() + val buffer = ChainedByteBuffer(limit = 16384) HandshakeMapSerializer.serialize(buffer, serializer.serialize(data), featureSet) val result = buffer.toBuffer() - result.print() val after = serializer.deserialize(HandshakeMapSerializer.deserialize(result, featureSet)) assertEquals(0, result.remaining()) if (matcher != null) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerDirect.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerDirect.kt index 6f6967dcbde514288c4adf8b870f1f98db5e1c77..a07f194fe10720c0e896611dc085cf0699382f07 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerDirect.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerDirect.kt @@ -20,7 +20,7 @@ package de.kuschku.libquassel.protocol.testutil import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print +import de.kuschku.libquassel.protocol.io.contentToString import de.kuschku.libquassel.protocol.serializers.primitive.QtSerializer import org.hamcrest.Matcher import org.hamcrest.MatcherAssert.assertThat @@ -32,10 +32,10 @@ fun <T> testQtSerializerDirect( featureSet: FeatureSet = FeatureSet.all(), matcher: Matcher<T>? = null ) { - val buffer = ChainedByteBuffer() + val buffer = ChainedByteBuffer(limit = 16384) serializer.serialize(buffer, data, featureSet) val result = buffer.toBuffer() - result.print() + println(result.contentToString()) val after = serializer.deserialize(result, featureSet) assertEquals(0, result.remaining()) if (matcher != null) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerVariant.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerVariant.kt index ea5bb24bc76bf6fe5467519dbe633d6f0501acf0..9ddb5bfd68943809e54521fbb6d25eeda255c8a1 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerVariant.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQtSerializerVariant.kt @@ -20,7 +20,6 @@ package de.kuschku.libquassel.protocol.testutil import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print import de.kuschku.libquassel.protocol.serializers.primitive.QVariantSerializer import de.kuschku.libquassel.protocol.serializers.primitive.QtSerializer import de.kuschku.libquassel.protocol.variant.QVariant @@ -34,10 +33,9 @@ fun <T> testQtSerializerVariant( featureSet: FeatureSet = FeatureSet.all(), matcher: Matcher<in T>? = null ) { - val buffer = ChainedByteBuffer() + val buffer = ChainedByteBuffer(limit = 16384) QVariantSerializer.serialize(buffer, QVariant.of(data, serializer), featureSet) val result = buffer.toBuffer() - result.print() val after = QVariantSerializer.deserialize(result, featureSet) assertEquals(0, result.remaining()) if (matcher != null) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerDirect.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerDirect.kt index aa7e70834c2b9eaeb1147517feb703ab3442b0c7..18aa2205783afafa1eecfe4afef5434d7d309339 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerDirect.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerDirect.kt @@ -20,7 +20,6 @@ package de.kuschku.libquassel.protocol.testutil import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print import de.kuschku.libquassel.protocol.serializers.primitive.QuasselSerializer import org.hamcrest.Matcher import org.hamcrest.MatcherAssert.assertThat @@ -32,11 +31,9 @@ fun <T> testQuasselSerializerDirect( featureSet: FeatureSet = FeatureSet.all(), matcher: Matcher<T>? = null ) { - val buffer = ChainedByteBuffer() + val buffer = ChainedByteBuffer(limit = 16384) serializer.serialize(buffer, data, featureSet) val result = buffer.toBuffer() - println("direct") - result.print() val after = serializer.deserialize(result, featureSet) assertEquals(0, result.remaining()) if (matcher != null) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerVariant.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerVariant.kt index fff25c72499310cd6f7c3bc80d0399d2350eb3e2..1cbff786c571140c93d97db5d28c496a43e20190 100644 --- a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerVariant.kt +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/testutil/testQuasselSerializerVariant.kt @@ -20,7 +20,6 @@ package de.kuschku.libquassel.protocol.testutil import de.kuschku.libquassel.protocol.features.FeatureSet import de.kuschku.libquassel.protocol.io.ChainedByteBuffer -import de.kuschku.libquassel.protocol.io.print import de.kuschku.libquassel.protocol.serializers.primitive.QVariantSerializer import de.kuschku.libquassel.protocol.serializers.primitive.QuasselSerializer import de.kuschku.libquassel.protocol.variant.QVariant @@ -34,10 +33,9 @@ fun <T> testQuasselSerializerVariant( featureSet: FeatureSet = FeatureSet.all(), matcher: Matcher<in T>? = null ) { - val buffer = ChainedByteBuffer() + val buffer = ChainedByteBuffer(limit = 16384) QVariantSerializer.serialize(buffer, QVariant.of(data, serializer), featureSet) val result = buffer.toBuffer() - result.print() val after = QVariantSerializer.deserialize(result, featureSet) assertEquals(0, result.remaining()) if (matcher != null) { diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/types/SignedIdTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/types/SignedIdTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..c3520885eb0b21cedcbbeae979f59eba373e3b72 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/types/SignedIdTest.kt @@ -0,0 +1,120 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.types + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +class SignedIdTest { + @Test + fun testNegativeOne() { + assertFalse(BufferId(-1).isValid()) + assertFalse(IdentityId(-1).isValid()) + assertFalse(MsgId(-1).isValid()) + assertFalse(NetworkId(-1).isValid()) + } + + @Test + fun testZero() { + assertFalse(BufferId(0).isValid()) + assertFalse(IdentityId(0).isValid()) + assertFalse(MsgId(0).isValid()) + assertFalse(NetworkId(0).isValid()) + } + + @Test + fun testMinimal() { + assertFalse(BufferId(Int.MIN_VALUE).isValid()) + assertFalse(IdentityId(Int.MIN_VALUE).isValid()) + assertFalse(MsgId(Long.MIN_VALUE).isValid()) + assertFalse(NetworkId(Int.MIN_VALUE).isValid()) + } + + @Test + fun testMaximum() { + assertTrue(BufferId(Int.MAX_VALUE).isValid()) + assertTrue(IdentityId(Int.MAX_VALUE).isValid()) + assertTrue(MsgId(Long.MAX_VALUE).isValid()) + assertTrue(NetworkId(Int.MAX_VALUE).isValid()) + } + + @Test + fun testSortOrder() { + assertEquals( + listOf( + BufferId(Int.MIN_VALUE), + BufferId(-1), + BufferId(0), + BufferId(Int.MAX_VALUE) + ), + listOf( + BufferId(Int.MAX_VALUE), + BufferId(Int.MIN_VALUE), + BufferId(0), + BufferId(-1) + ).sorted() + ) + + assertEquals( + listOf( + IdentityId(Int.MIN_VALUE), + IdentityId(-1), + IdentityId(0), + IdentityId(Int.MAX_VALUE) + ), + listOf( + IdentityId(Int.MAX_VALUE), + IdentityId(Int.MIN_VALUE), + IdentityId(0), + IdentityId(-1) + ).sorted() + ) + + assertEquals( + listOf( + MsgId(Long.MIN_VALUE), + MsgId(-1), + MsgId(0), + MsgId(Long.MAX_VALUE) + ), + listOf( + MsgId(Long.MAX_VALUE), + MsgId(Long.MIN_VALUE), + MsgId(0), + MsgId(-1) + ).sorted() + ) + + assertEquals( + listOf( + NetworkId(Int.MIN_VALUE), + NetworkId(-1), + NetworkId(0), + NetworkId(Int.MAX_VALUE) + ), + listOf( + NetworkId(Int.MAX_VALUE), + NetworkId(Int.MIN_VALUE), + NetworkId(0), + NetworkId(-1) + ).sorted() + ) + } +} diff --git a/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/variant/QVariantTest.kt b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/variant/QVariantTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..df0d34f826e364171fa0e76c06ecf378e9322b57 --- /dev/null +++ b/protocol/src/test/kotlin/de/kuschku/libquassel/protocol/variant/QVariantTest.kt @@ -0,0 +1,46 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2021 Janne Mareike Koschinski + * Copyright (c) 2021 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.protocol.variant + +import de.kuschku.libquassel.protocol.testutil.byteBufferOf +import de.kuschku.libquassel.protocol.variant.QtType +import de.kuschku.libquassel.protocol.variant.qVariant +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +class QVariantTest { + @Test + fun testString() { + assertEquals( + "QVariant(ByteBufferSerializer, DEADBEEF)", + qVariant( + byteBufferOf(0xDEu, 0xADu, 0xBEu, 0xEFu), + QtType.QByteArray + ).toString() + ) + assertEquals( + "QVariant(StringSerializerUtf16, DEADBEEF)", + qVariant( + "DEADBEEF", + QtType.QString + ).toString() + ) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e4af358e37b2cdd5b9e063004b4a2453b5885d62..eef525f65a266197615cb4ca39002a2e2d22dcaf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,5 +23,6 @@ rootProject.buildFileName = "build.gradle.kts" include( ":app", ":bitflags", - ":protocol" + ":protocol", + ":coverage-annotations" )