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 ce8224fea6f7cd104208f3b0648044ee255d467c..04234b65491145fc41d40a15cc8c73713ef627a7 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 32ad22642fa65d692ff1e58738fe5e7319affee0..e3a5f38b459e2fff9f581376d93d39ee697d7522 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 1e54f7b0a905202f29152d108f7eb5206250d424..0588c5b685dea74e7db3eecfb63620476286feb0 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 dab50bc213512d3142287740539ea2a030a2c507..25930f827e46ed4333fac3d055ccb4b4191b12af 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 7627c2be9c4d9cb68998ff12cb938703a7c73c71..b738b66e502a7e6ae10d444074485786505a4dde 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 4737c747b77d8f825a515c0a7b4e1ab95b0e085e..286e2214bac825eaa64ba507c77106d76c7c317a 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 1cc549b06ce372032bbd177a6fab05aa146d2858..40e2300ff9ecad3142e99ce7588c2dc6b5ea6d2e 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 f2c897ae4da4103c3d30cc166da49c417c66d682..96768399bea13577f9ce210cdb7de1a63efe82ff 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 653bc953679a98c9129e87fef02c9412d00adc99..765cf2aeba88befdd65917c389d3d3996828b608 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 793adeafcb35365a9968f382446e2603c79b1b67..0ece62be3fed882879055d70afe04467499e52df 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 40fc1089add2c75d6d94397f3d08dd332e9aecb3..9e6d03f2e2ef82231557d41bc106e846a058d465 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 357bc67bc04acfa1de21c3432776d143c9dfd6c1..2890ffa22b7fec62cb3574cfe33413f017661579 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 7d1f6705894cced48dc83132acdc9ebe7696ee6b..996e5072594483ca222cf2b98b385768c1b16270 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 0000000000000000000000000000000000000000..4ea7d9039e607836bc4bb308d346e3d0aa593572 --- /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 0000000000000000000000000000000000000000..595ca30b263ef56aafee999709a594a3f7bd6568 --- /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 dbf7c7bd9140483f18015c49e47fba6222835c62..59d4f7c130073c0e51d774938d9686aa16e44694 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 0000000000000000000000000000000000000000..e31ba6e980dd0cc0e8cf67b8394d8d17f740fe79 --- /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 0000000000000000000000000000000000000000..efbc8a452d76027a3da9512a14ac6bf3f99e03e4 --- /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 0000000000000000000000000000000000000000..e913014b7a4123d59756e411e6b37e21d9abb7e7 --- /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 0000000000000000000000000000000000000000..a082f18054feae0c8fa6f6f55c26a4bcb09144b9 --- /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 0000000000000000000000000000000000000000..0b72810b8be4051d334f15eb05c201360a433675 --- /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 0000000000000000000000000000000000000000..1315215ef3a81723a81f885bd9cce59567c77c7c --- /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 91997768609729600e11b807219d3ddf57c59031..5f70f09b11745c0dcbc8bbff9ce81615e25ab162 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 76057f15745fcbb009ed3b8875cf35eb4b194780..52e0fe81db563126618dc9e4d1eadbf8a86644f0 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 34dd4ad658d57085f8a104852d5c02b6f7fbd799..a4f64c131999dfed506d0efec059e494d6c5a8ed 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 d0e227107ad7d92b6c1582826e6cfe323cd26d0f..3e7c49f0cf0cadb1fba972126934ac06e793f10a 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 70e7011701ba253fd64b0a45c2c88b8f472eb2db..c19cafe5d70dee2227e4108100571eddd8c66215 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 0000000000000000000000000000000000000000..0fa7c85e39b2f694b88feaceac63d5555c7737f9 --- /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 c1ad766257539968183c8bc5b8b9d60abdbd3ffc..2fd34c3c27928635570f17ff21f230a4578b7ca5 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 56692a983a9bb6ade35a0dac394e996d5771c22b..fcb03de52978174bbe9181a06227054a470853e5 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 0000000000000000000000000000000000000000..10bc255b167e1a2d2bb6d9578290d2733679d61c --- /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 0000000000000000000000000000000000000000..8575be4683c71e2f50511f1bcd1aa2e0bd8914f4 --- /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) + } +}