From 2792ca9ab07eab08b01dc8cb7e1ab4bf0884210f Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Tue, 16 Feb 2021 21:26:10 +0100 Subject: [PATCH] Implement signal proxy messages --- .../protocol/models/DccIpDetectionMode.kt | 3 +- .../protocol/models/DccPortSelectionMode.kt | 3 +- .../protocol/models/NetworkLayerProtocol.kt | 3 +- .../protocol/models/SignalProxyMessage.kt | 64 ++++++++++++++++++- .../libquassel/protocol/models/TimeSpec.kt | 3 +- .../protocol/models/flags/BufferActivity.kt | 3 +- .../protocol/models/flags/BufferType.kt | 3 +- .../protocol/models/flags/MessageFlag.kt | 3 +- .../protocol/models/flags/MessageType.kt | 3 +- .../protocol/models/types/QtType.kt | 3 +- .../protocol/models/types/QuasselType.kt | 3 +- .../serializers/HandshakeSerializer.kt | 3 +- .../NoSerializerForTypeException.kt | 4 +- .../SignalProxyMessageSerializer.kt | 64 +++++++++++++++++++ .../serializers/SignalProxySerializer.kt | 44 +++++++++++++ .../serializers/qt/StringSerializer.kt | 5 +- .../signalproxy/HeartBeatReplySerializer.kt | 22 +++++++ .../signalproxy/HeartBeatSerializer.kt | 22 +++++++ .../signalproxy/InitDataSerializer.kt | 28 ++++++++ .../signalproxy/InitRequestSerializer.kt | 25 ++++++++ .../serializers/signalproxy/RpcSerializer.kt | 24 +++++++ .../serializers/signalproxy/SyncSerializer.kt | 28 ++++++++ .../protocol/variant/QVariantList.kt | 5 ++ .../protocol/variant/QVariantMap.kt | 7 ++ .../protocol/testutil/deserialize.kt | 30 ++++++++- .../testutil/handshakeSerializerTest.kt | 3 +- .../libquassel/protocol/testutil/serialize.kt | 17 ++++- .../testutil/signalProxySerializerTest.kt | 52 +++++++++++++++ .../testutil/testHandshakeSerializerDirect.kt | 3 +- .../testHandshakeSerializerEncoded.kt | 3 +- .../testSignalProxySerializerDirect.kt | 38 +++++++++++ .../testSignalProxySerializerEncoded.kt | 46 +++++++++++++ 32 files changed, 546 insertions(+), 21 deletions(-) create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxyMessageSerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxySerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializer.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializer.kt create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/signalProxySerializerTest.kt create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerDirect.kt create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerEncoded.kt diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccIpDetectionMode.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccIpDetectionMode.kt index ce8224f..04234b6 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccIpDetectionMode.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccIpDetectionMode.kt @@ -35,7 +35,8 @@ enum class DccIpDetectionMode( Manual(0x01u); companion object { - private val values = values().associateBy(DccIpDetectionMode::value) + private val values = enumValues<DccIpDetectionMode>() + .associateBy(DccIpDetectionMode::value) /** * Obtain from underlying representation diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccPortSelectionMode.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccPortSelectionMode.kt index 32ad226..e3a5f38 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccPortSelectionMode.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/DccPortSelectionMode.kt @@ -35,7 +35,8 @@ enum class DccPortSelectionMode( Manual(0x01u); companion object { - private val values = values().associateBy(DccPortSelectionMode::value) + private val values = enumValues<DccPortSelectionMode>() + .associateBy(DccPortSelectionMode::value) /** * Obtain from underlying representation diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkLayerProtocol.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkLayerProtocol.kt index 1e54f7b..0588c5b 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkLayerProtocol.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkLayerProtocol.kt @@ -53,7 +53,8 @@ enum class NetworkLayerProtocol( UnknownNetworkLayerProtocol(0xFFu); companion object { - private val values = values().associateBy(NetworkLayerProtocol::value) + private val values = enumValues<NetworkLayerProtocol>() + .associateBy(NetworkLayerProtocol::value) /** * Obtain from underlying representation diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt index dab50bc..25930f8 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/SignalProxyMessage.kt @@ -4,11 +4,29 @@ import de.justjanne.libquassel.protocol.variant.QVariantList import de.justjanne.libquassel.protocol.variant.QVariantMap import org.threeten.bp.Instant +/** + * Model classes for messages exchanged with the signal proxy + */ sealed class SignalProxyMessage { + /** + * Sync message, representing an RPC call on a specific object + */ data class Sync( + /** + * Type of the specified object + */ val className: String, + /** + * Name/ID of the specified object + */ val objectName: String, + /** + * Name of the function/slot to be called on the object + */ val slotName: String, + /** + * Parameters to the function call + */ val params: QVariantList ) : SignalProxyMessage() { override fun toString(): String { @@ -16,8 +34,17 @@ sealed class SignalProxyMessage { } } - data class RpcCall( + /** + * RPC message, representing an RPC call on the global client object + */ + data class Rpc( + /** + * Name of the function/slot to be called on the object + */ val slotName: String, + /** + * Parameters to the function call + */ val params: QVariantList ) : SignalProxyMessage() { override fun toString(): String { @@ -25,8 +52,18 @@ sealed class SignalProxyMessage { } } + /** + * Init request message, representing a request to get the current state of a + * specified object + */ data class InitRequest( + /** + * Type of the specified object + */ val className: String, + /** + * Name/ID of the specified object + */ val objectName: String ) : SignalProxyMessage() { override fun toString(): String { @@ -34,9 +71,22 @@ sealed class SignalProxyMessage { } } + /** + * Init data message, representing a message with the current state of a + * specified object + */ data class InitData( + /** + * Type of the specified object + */ val className: String, + /** + * Name/ID of the specified object + */ val objectName: String, + /** + * Current state of the specified object + */ val initData: QVariantMap ) : SignalProxyMessage() { override fun toString(): String { @@ -44,7 +94,13 @@ sealed class SignalProxyMessage { } } + /** + * Heart beat message to keep the connection alive and measure latency + */ data class HeartBeat( + /** + * Local timestamp of the moment the message was sent + */ val timestamp: Instant ) : SignalProxyMessage() { override fun toString(): String { @@ -52,7 +108,13 @@ sealed class SignalProxyMessage { } } + /** + * Heart beat reply message as response to [HeartBeat] + */ data class HeartBeatReply( + /** + * Local timestamp of the moment the original heartbeat was sent + */ val timestamp: Instant ) : SignalProxyMessage() { override fun toString(): String { diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/TimeSpec.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/TimeSpec.kt index 7627c2b..b738b66 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/TimeSpec.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/TimeSpec.kt @@ -58,7 +58,8 @@ enum class TimeSpec( OffsetFromUTC(3); companion object { - private val map = values().associateBy(TimeSpec::value) + private val map = enumValues<TimeSpec>() + .associateBy(TimeSpec::value) /** * Obtain a zone specification by its underlying representation diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt index 4737c74..286e221 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt @@ -45,7 +45,8 @@ enum class BufferActivity( Highlight(0x04u); companion object : Flags<UInt, BufferActivity> { - private val values = values().associateBy(BufferActivity::value) + private val values = enumValues<BufferActivity>() + .associateBy(BufferActivity::value) override val all: BufferActivities = values.values.toEnumSet() } } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferType.kt index 1cc549b..40e2300 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferType.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferType.kt @@ -50,7 +50,8 @@ enum class BufferType( Group(0x08u); companion object : Flags<UShort, BufferType> { - private val values = values().associateBy(BufferType::value) + private val values = enumValues<BufferType>() + .associateBy(BufferType::value) override val all: BufferTypes = values.values.toEnumSet() } } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageFlag.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageFlag.kt index f2c897a..9676839 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageFlag.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageFlag.kt @@ -65,7 +65,8 @@ enum class MessageFlag( Backlog(0x80u); companion object : Flags<UInt, MessageFlag> { - private val values = values().associateBy(MessageFlag::value) + private val values = enumValues<MessageFlag>() + .associateBy(MessageFlag::value) override val all: MessageFlags = values.values.toEnumSet() } } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageType.kt index 653bc95..765cf2a 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageType.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/MessageType.kt @@ -125,7 +125,8 @@ enum class MessageType( Markerline(0x40000u); companion object : Flags<UInt, MessageType> { - private val values = values().associateBy(MessageType::value) + private val values = enumValues<MessageType>() + .associateBy(MessageType::value) override val all: MessageTypes = values.values.toEnumSet() } } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QtType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QtType.kt index 793adea..0ece62b 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QtType.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QtType.kt @@ -204,7 +204,8 @@ enum class QtType( } companion object { - private val values = values().associateBy(QtType::id) + private val values = enumValues<QtType>() + .associateBy(QtType::id) /** * Obtain a QtType by its underlying representation diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QuasselType.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QuasselType.kt index 40fc108..9e6d03f 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QuasselType.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/types/QuasselType.kt @@ -151,7 +151,8 @@ enum class QuasselType( } companion object { - private val values = values().associateBy(QuasselType::typeName) + private val values = enumValues<QuasselType>() + .associateBy(QuasselType::typeName) /** * Obtain a QtType by its standardized name diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/HandshakeSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/HandshakeSerializer.kt index 357bc67..2890ffa 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/HandshakeSerializer.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/HandshakeSerializer.kt @@ -19,12 +19,13 @@ package de.justjanne.libquassel.protocol.serializers +import de.justjanne.libquassel.protocol.models.HandshakeMessage import de.justjanne.libquassel.protocol.variant.QVariantMap /** * High-level serializer for handshake messages. */ -interface HandshakeSerializer<T> { +interface HandshakeSerializer<T : HandshakeMessage> { /** * The underlying handshake message type this serializer can (de-)serialize. * Used for type-safe serializer autodiscovery. diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/NoSerializerForTypeException.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/NoSerializerForTypeException.kt index 7d1f670..996e507 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/NoSerializerForTypeException.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/NoSerializerForTypeException.kt @@ -83,11 +83,11 @@ sealed class NoSerializerForTypeException : Exception() { * Exception describing a missing serializer condition for a signal proxy type */ data class SignalProxy( - private val type: String, + private val type: Int, private val javaType: Class<*>? = null ) : NoSerializerForTypeException() { override fun toString(): String { - return "NoSerializerForTypeException.Handshake(type='$type', javaType=$javaType)" + return "NoSerializerForTypeException.SignalProxy(type='$type', javaType=$javaType)" } } } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxyMessageSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxyMessageSerializer.kt new file mode 100644 index 0000000..4ea7d90 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxyMessageSerializer.kt @@ -0,0 +1,64 @@ +package de.justjanne.libquassel.protocol.serializers + +import de.justjanne.libquassel.protocol.features.FeatureSet +import de.justjanne.libquassel.protocol.io.ChainedByteBuffer +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.serializers.qt.QVariantListSerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.HeartBeatReplySerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.HeartBeatSerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.InitDataSerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.InitRequestSerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.RpcSerializer +import de.justjanne.libquassel.protocol.serializers.signalproxy.SyncSerializer +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import java.nio.ByteBuffer + +/** + * Singleton object containing all serializers for handshake message types + */ +object SignalProxyMessageSerializer : PrimitiveSerializer<SignalProxyMessage> { + override val javaType: Class<out SignalProxyMessage> = SignalProxyMessage::class.java + + private fun serializeToList(data: SignalProxyMessage): QVariantList = + when (data) { + is SignalProxyMessage.Sync -> + SyncSerializer.serialize(data) + is SignalProxyMessage.Rpc -> + RpcSerializer.serialize(data) + is SignalProxyMessage.InitRequest -> + InitRequestSerializer.serialize(data) + is SignalProxyMessage.InitData -> + InitDataSerializer.serialize(data) + is SignalProxyMessage.HeartBeat -> + HeartBeatSerializer.serialize(data) + is SignalProxyMessage.HeartBeatReply -> + HeartBeatReplySerializer.serialize(data) + } + + private fun deserializeFromList(data: QVariantList): SignalProxyMessage = + when (val type = data.firstOrNull().into<Int>(0)) { + SyncSerializer.type -> + SyncSerializer.deserialize(data) + RpcSerializer.type -> + RpcSerializer.deserialize(data) + InitRequestSerializer.type -> + InitRequestSerializer.deserialize(data) + InitDataSerializer.type -> + InitDataSerializer.deserialize(data) + HeartBeatSerializer.type -> + HeartBeatSerializer.deserialize(data) + HeartBeatReplySerializer.type -> + HeartBeatReplySerializer.deserialize(data) + else -> + throw NoSerializerForTypeException.SignalProxy(type) + } + + override fun serialize(buffer: ChainedByteBuffer, data: SignalProxyMessage, featureSet: FeatureSet) { + QVariantListSerializer.serialize(buffer, serializeToList(data), featureSet) + } + + override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): SignalProxyMessage { + return deserializeFromList(QVariantListSerializer.deserialize(buffer, featureSet)) + } +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxySerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxySerializer.kt new file mode 100644 index 0000000..595ca30 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/SignalProxySerializer.kt @@ -0,0 +1,44 @@ +/* + * 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.justjanne.libquassel.protocol.serializers + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.variant.QVariantList + +/** + * High-level serializer for signal proxy messages. + */ +interface SignalProxySerializer<T : SignalProxyMessage> { + /** + * The underlying signal proxy message type this serializer can (de-)serialize. + * Used for type-safe serializer autodiscovery. + */ + val type: Int + + /** + * Serialize a signal proxy message into a [QVariantList] (for further serialization) + */ + fun serialize(data: T): QVariantList + + /** + * Deserialize a signal proxy message from a [QVariantList] + */ + fun deserialize(data: QVariantList): T +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt index dbf7c7b..59d4f7c 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializer.kt @@ -86,7 +86,10 @@ abstract class StringSerializer( /** * Deserialize a string from a given byte slice */ - fun deserializeRaw(data: ByteBuffer): String { + fun deserializeRaw(data: ByteBuffer?): String { + if (data == null) { + return "" + } if (nullLimited) { data.limit(removeNullBytes(data.limit())) } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializer.kt new file mode 100644 index 0000000..e31ba6e --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializer.kt @@ -0,0 +1,22 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import org.threeten.bp.Instant + +object HeartBeatReplySerializer : SignalProxySerializer<SignalProxyMessage.HeartBeatReply> { + override val type: Int = 6 + + override fun serialize(data: SignalProxyMessage.HeartBeatReply) = listOf( + qVariant(type, QtType.Int), + qVariant(data.timestamp, QtType.QDateTime) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeatReply( + data[1].into(Instant.EPOCH) + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializer.kt new file mode 100644 index 0000000..efbc8a4 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializer.kt @@ -0,0 +1,22 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import org.threeten.bp.Instant + +object HeartBeatSerializer : SignalProxySerializer<SignalProxyMessage.HeartBeat> { + override val type: Int = 5 + + override fun serialize(data: SignalProxyMessage.HeartBeat) = listOf( + qVariant(type, QtType.Int), + qVariant(data.timestamp, QtType.QDateTime) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeat( + data[1].into(Instant.EPOCH) + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializer.kt new file mode 100644 index 0000000..e913014 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializer.kt @@ -0,0 +1,28 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8 +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import de.justjanne.libquassel.protocol.variant.toVariantList +import de.justjanne.libquassel.protocol.variant.toVariantMap +import java.nio.ByteBuffer + +object InitDataSerializer : SignalProxySerializer<SignalProxyMessage.InitData> { + override val type: Int = 4 + + override fun serialize(data: SignalProxyMessage.InitData) = listOf( + qVariant(type, QtType.Int), + qVariant(StringSerializerUtf8.serializeRaw(data.className), QtType.QByteArray), + qVariant(StringSerializerUtf8.serializeRaw(data.objectName), QtType.QByteArray), + ) + data.initData.toVariantList() + + override fun deserialize(data: QVariantList) = SignalProxyMessage.InitData( + StringSerializerUtf8.deserializeRaw(data[1].into<ByteBuffer>()), + StringSerializerUtf8.deserializeRaw(data[2].into<ByteBuffer>()), + data.drop(3).toVariantMap() + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializer.kt new file mode 100644 index 0000000..a082f18 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializer.kt @@ -0,0 +1,25 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8 +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import java.nio.ByteBuffer + +object InitRequestSerializer : SignalProxySerializer<SignalProxyMessage.InitRequest> { + override val type: Int = 3 + + override fun serialize(data: SignalProxyMessage.InitRequest) = listOf( + qVariant(InitDataSerializer.type, QtType.Int), + qVariant(StringSerializerUtf8.serializeRaw(data.className), QtType.QByteArray), + qVariant(StringSerializerUtf8.serializeRaw(data.objectName), QtType.QByteArray), + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.InitRequest( + StringSerializerUtf8.deserializeRaw(data[1].into<ByteBuffer>()), + StringSerializerUtf8.deserializeRaw(data[2].into<ByteBuffer>()) + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializer.kt new file mode 100644 index 0000000..0b72810 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializer.kt @@ -0,0 +1,24 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8 +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import java.nio.ByteBuffer + +object RpcSerializer : SignalProxySerializer<SignalProxyMessage.Rpc> { + override val type: Int = 2 + + override fun serialize(data: SignalProxyMessage.Rpc) = listOf( + qVariant(SyncSerializer.type, QtType.Int), + qVariant(StringSerializerUtf8.serializeRaw(data.slotName), QtType.QByteArray) + ) + data.params + + override fun deserialize(data: QVariantList) = SignalProxyMessage.Rpc( + StringSerializerUtf8.deserializeRaw(data[1].into<ByteBuffer>()), + data.drop(2) + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializer.kt new file mode 100644 index 0000000..1315215 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializer.kt @@ -0,0 +1,28 @@ +package de.justjanne.libquassel.protocol.serializers.signalproxy + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8 +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.into +import de.justjanne.libquassel.protocol.variant.qVariant +import java.nio.ByteBuffer + +object SyncSerializer : SignalProxySerializer<SignalProxyMessage.Sync> { + override val type: Int = 1 + + override fun serialize(data: SignalProxyMessage.Sync) = listOf( + qVariant(type, QtType.Int), + qVariant(StringSerializerUtf8.serializeRaw(data.className), QtType.QByteArray), + qVariant(StringSerializerUtf8.serializeRaw(data.objectName), QtType.QByteArray), + qVariant(StringSerializerUtf8.serializeRaw(data.slotName), QtType.QByteArray) + ) + data.params + + override fun deserialize(data: QVariantList) = SignalProxyMessage.Sync( + StringSerializerUtf8.deserializeRaw(data[1].into<ByteBuffer>()), + StringSerializerUtf8.deserializeRaw(data[2].into<ByteBuffer>()), + StringSerializerUtf8.deserializeRaw(data[3].into<ByteBuffer>()), + data.drop(4) + ) +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantList.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantList.kt index 9199776..5f70f09 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantList.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantList.kt @@ -4,3 +4,8 @@ package de.justjanne.libquassel.protocol.variant * Simple alias for a generic QVariantList type */ typealias QVariantList = List<QVariant_> + +fun QVariantList.toVariantMap(): QVariantMap = + this.zipWithNext().map { (key, value) -> + Pair(key.into(""), value) + }.toMap() diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantMap.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantMap.kt index 76057f1..52e0fe8 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantMap.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/variant/QVariantMap.kt @@ -1,6 +1,13 @@ package de.justjanne.libquassel.protocol.variant +import de.justjanne.libquassel.protocol.models.types.QtType + /** * Simple alias for a generic QVariantMap type */ typealias QVariantMap = Map<String, QVariant_> + +fun QVariantMap.toVariantList(): QVariantList = + this.toList().flatMap { (key, value) -> + listOf(qVariant(key, QtType.QString), value) + } diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/deserialize.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/deserialize.kt index 34dd4ad..a4f64c1 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/deserialize.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/deserialize.kt @@ -19,9 +19,13 @@ package de.justjanne.libquassel.protocol.testutil import de.justjanne.libquassel.protocol.features.FeatureSet +import de.justjanne.libquassel.protocol.models.HandshakeMessage +import de.justjanne.libquassel.protocol.models.SignalProxyMessage import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer import de.justjanne.libquassel.protocol.serializers.qt.HandshakeMapSerializer +import de.justjanne.libquassel.protocol.serializers.qt.QVariantListSerializer import org.hamcrest.Matcher import org.hamcrest.MatcherAssert.assertThat import org.junit.jupiter.api.Assertions.assertEquals @@ -57,7 +61,7 @@ fun <T> testDeserialize( assertEquals(data, after) } -fun <T> testDeserialize( +fun <T : HandshakeMessage> testDeserialize( serializer: HandshakeSerializer<T>, matcher: Matcher<in T>, buffer: ByteBuffer, @@ -68,7 +72,7 @@ fun <T> testDeserialize( assertThat(after, matcher) } -fun <T> testDeserialize( +fun <T : HandshakeMessage> testDeserialize( serializer: HandshakeSerializer<T>, data: T, buffer: ByteBuffer, @@ -78,3 +82,25 @@ fun <T> testDeserialize( val after = serializer.deserialize(map) assertEquals(data, after) } + +fun <T : SignalProxyMessage> testDeserialize( + serializer: SignalProxySerializer<T>, + matcher: Matcher<in T>, + buffer: ByteBuffer, + featureSet: FeatureSet = FeatureSet.all() +) { + val list = deserialize(QVariantListSerializer, buffer, featureSet) + val after = serializer.deserialize(list) + assertThat(after, matcher) +} + +fun <T : SignalProxyMessage> testDeserialize( + serializer: SignalProxySerializer<T>, + data: T, + buffer: ByteBuffer, + featureSet: FeatureSet = FeatureSet.all() +) { + val list = deserialize(QVariantListSerializer, buffer, featureSet) + val after = serializer.deserialize(list) + assertEquals(data, after) +} diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/handshakeSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/handshakeSerializerTest.kt index d0e2271..3e7c49f 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/handshakeSerializerTest.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/handshakeSerializerTest.kt @@ -19,11 +19,12 @@ package de.justjanne.libquassel.protocol.testutil import de.justjanne.libquassel.protocol.features.FeatureSet +import de.justjanne.libquassel.protocol.models.HandshakeMessage import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer import org.hamcrest.Matcher import java.nio.ByteBuffer -fun <T> handshakeSerializerTest( +fun <T : HandshakeMessage> handshakeSerializerTest( serializer: HandshakeSerializer<T>, value: T, encoded: ByteBuffer? = null, diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/serialize.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/serialize.kt index 70e7011..c19cafe 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/serialize.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/serialize.kt @@ -20,9 +20,13 @@ package de.justjanne.libquassel.protocol.testutil import de.justjanne.libquassel.protocol.features.FeatureSet import de.justjanne.libquassel.protocol.io.ChainedByteBuffer +import de.justjanne.libquassel.protocol.models.HandshakeMessage +import de.justjanne.libquassel.protocol.models.SignalProxyMessage import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer import de.justjanne.libquassel.protocol.serializers.qt.HandshakeMapSerializer +import de.justjanne.libquassel.protocol.serializers.qt.QVariantListSerializer import de.justjanne.libquassel.protocol.testutil.matchers.ByteBufferMatcher import org.hamcrest.MatcherAssert.assertThat import java.nio.ByteBuffer @@ -47,7 +51,7 @@ fun <T> testSerialize( assertThat(after, ByteBufferMatcher(buffer)) } -fun <T> testSerialize( +fun <T : HandshakeMessage> testSerialize( serializer: HandshakeSerializer<T>, data: T, buffer: ByteBuffer, @@ -57,3 +61,14 @@ fun <T> testSerialize( val after = serialize(HandshakeMapSerializer, map, featureSet) assertThat(after, ByteBufferMatcher(buffer)) } + +fun <T : SignalProxyMessage> testSerialize( + serializer: SignalProxySerializer<T>, + data: T, + buffer: ByteBuffer, + featureSet: FeatureSet = FeatureSet.all() +) { + val list = serializer.serialize(data) + val after = serialize(QVariantListSerializer, list, featureSet) + assertThat(after, ByteBufferMatcher(buffer)) +} diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/signalProxySerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/signalProxySerializerTest.kt new file mode 100644 index 0000000..0fa7c85 --- /dev/null +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/signalProxySerializerTest.kt @@ -0,0 +1,52 @@ +/* + * 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.justjanne.libquassel.protocol.testutil + +import de.justjanne.libquassel.protocol.features.FeatureSet +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import org.hamcrest.Matcher +import java.nio.ByteBuffer + +fun <T : SignalProxyMessage> signalProxySerializerTest( + serializer: SignalProxySerializer<T>, + value: T, + encoded: ByteBuffer? = null, + matcher: ((T) -> Matcher<T>)? = null, + featureSets: List<FeatureSet> = listOf(FeatureSet.none(), 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) { + testSignalProxySerializerDirect(serializer, value) + testSignalProxySerializerEncoded(serializer, value, featureSet) + } +} diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerDirect.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerDirect.kt index c1ad766..2fd34c3 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerDirect.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerDirect.kt @@ -18,12 +18,13 @@ */ package de.justjanne.libquassel.protocol.testutil +import de.justjanne.libquassel.protocol.models.HandshakeMessage import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer import org.hamcrest.Matcher import org.hamcrest.MatcherAssert.assertThat import org.junit.jupiter.api.Assertions.assertEquals -fun <T> testHandshakeSerializerDirect( +fun <T : HandshakeMessage> testHandshakeSerializerDirect( serializer: HandshakeSerializer<T>, data: T, matcher: Matcher<T>? = null diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt index 56692a9..fcb03de 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testHandshakeSerializerEncoded.kt @@ -20,13 +20,14 @@ package de.justjanne.libquassel.protocol.testutil import de.justjanne.libquassel.protocol.features.FeatureSet import de.justjanne.libquassel.protocol.io.ChainedByteBuffer +import de.justjanne.libquassel.protocol.models.HandshakeMessage import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer import de.justjanne.libquassel.protocol.serializers.qt.HandshakeMapSerializer import org.hamcrest.Matcher import org.hamcrest.MatcherAssert.assertThat import org.junit.jupiter.api.Assertions.assertEquals -fun <T> testHandshakeSerializerEncoded( +fun <T : HandshakeMessage> testHandshakeSerializerEncoded( serializer: HandshakeSerializer<T>, data: T, featureSet: FeatureSet = FeatureSet.all(), diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerDirect.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerDirect.kt new file mode 100644 index 0000000..10bc255 --- /dev/null +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerDirect.kt @@ -0,0 +1,38 @@ +/* + * 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.justjanne.libquassel.protocol.testutil + +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Assertions.assertEquals + +fun <T : SignalProxyMessage> testSignalProxySerializerDirect( + serializer: SignalProxySerializer<T>, + data: T, + matcher: Matcher<T>? = null +) { + val after = serializer.deserialize(serializer.serialize(data)) + if (matcher != null) { + assertThat(after, matcher) + } else { + assertEquals(data, after) + } +} diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerEncoded.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerEncoded.kt new file mode 100644 index 0000000..8575be4 --- /dev/null +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testSignalProxySerializerEncoded.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.justjanne.libquassel.protocol.testutil + +import de.justjanne.libquassel.protocol.features.FeatureSet +import de.justjanne.libquassel.protocol.io.ChainedByteBuffer +import de.justjanne.libquassel.protocol.models.SignalProxyMessage +import de.justjanne.libquassel.protocol.serializers.SignalProxySerializer +import de.justjanne.libquassel.protocol.serializers.qt.QVariantListSerializer +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Assertions.assertEquals + +fun <T : SignalProxyMessage> testSignalProxySerializerEncoded( + serializer: SignalProxySerializer<T>, + data: T, + featureSet: FeatureSet = FeatureSet.all(), + matcher: Matcher<T>? = null +) { + val buffer = ChainedByteBuffer(limit = 16384) + QVariantListSerializer.serialize(buffer, serializer.serialize(data), featureSet) + val result = buffer.toBuffer() + val after = serializer.deserialize(QVariantListSerializer.deserialize(result, featureSet)) + assertEquals(0, result.remaining()) + if (matcher != null) { + assertThat(after, matcher) + } else { + assertEquals(data, after) + } +} -- GitLab