From be20250ec4f6a31d64ca94b2b514e2a4bbd54839 Mon Sep 17 00:00:00 2001
From: Janne Mareike Koschinski <janne@kuschku.de>
Date: Sun, 28 Feb 2021 18:10:14 +0100
Subject: [PATCH] Further code quality improvements

---
 .../CoverageConverterPlugin.kt                |   3 +-
 libquassel-protocol/build.gradle.kts          |   1 +
 .../libquassel/protocol/io/ByteBufferUtil.kt  |   8 +-
 .../protocol/models/BackendInfoSerializer.kt  |   2 +-
 .../protocol/models/HandshakeMessage.kt       |   6 +-
 .../libquassel/protocol/models/NetworkInfo.kt |  50 +--
 .../protocol/models/ids/SignedId.kt           |   2 -
 .../protocol/models/types/QuasselType.kt      |   9 +-
 .../SignalProxyMessageSerializer.kt           |   2 +-
 .../handshake/CoreSetupDataSerializer.kt      |  14 +-
 .../handshake/SessionInitSerializer.kt        |  19 +-
 .../serializers/qt/ByteBufferSerializer.kt    |   2 +
 .../serializers/qt/QVariantSerializer.kt      |   6 +
 .../quassel/BufferInfoSerializer.kt           |   1 +
 .../serializers/quassel/IdentitySerializer.kt |  34 +++
 .../quassel/IrcChannelSerializer.kt           |  34 +++
 .../serializers/quassel/IrcUserSerializer.kt  |  34 +++
 .../signalproxy/HeartBeatReplySerializer.kt   |   2 +-
 .../signalproxy/HeartBeatSerializer.kt        |   2 +-
 .../signalproxy/InitDataSerializer.kt         |   4 +-
 .../signalproxy/InitRequestSerializer.kt      |   6 +-
 .../serializers/signalproxy/RpcSerializer.kt  |   4 +-
 .../serializers/signalproxy/SyncSerializer.kt |   6 +-
 .../protocol/syncables/AliasManager.kt        |  24 +-
 .../protocol/syncables/BacklogManager.kt      |   2 +-
 .../protocol/syncables/BufferSyncer.kt        |  24 +-
 .../protocol/syncables/BufferViewConfig.kt    |  34 +--
 .../protocol/syncables/BufferViewManager.kt   |  27 +-
 .../protocol/syncables/CertManager.kt         |  22 +-
 .../libquassel/protocol/syncables/CoreInfo.kt |  18 +-
 .../protocol/syncables/DccConfig.kt           |  20 +-
 .../syncables/HighlightRuleManager.kt         |  18 +-
 .../libquassel/protocol/syncables/Identity.kt |  21 +-
 .../protocol/syncables/IgnoreListManager.kt   |  12 +
 .../protocol/syncables/IrcChannel.kt          |  44 +--
 .../protocol/syncables/IrcListHelper.kt       |   2 +-
 .../libquassel/protocol/syncables/IrcUser.kt  |  51 +---
 .../libquassel/protocol/syncables/Network.kt  | 142 +++------
 .../protocol/syncables/NetworkConfig.kt       |  20 +-
 .../syncables/StatefulSyncableObject.kt       |  48 +++
 .../protocol/syncables/SyncableObject.kt      |  23 +-
 .../protocol/syncables/SyncableStub.kt        |   9 +-
 .../protocol/syncables/state/NetworkState.kt  |  57 +++-
 .../syncables/stubs/BufferSyncerStub.kt       |   4 +-
 .../protocol/syncables/stubs/NetworkStub.kt   |   1 +
 .../util/{ => collections}/indices.kt         |   2 +-
 .../util/{plus.kt => collections/insert.kt}   |   5 +-
 .../protocol/util/{ => collections}/move.kt   |  15 +-
 .../protocol/util/{ => collections}/pairs.kt  |   5 +-
 .../protocol/util/{ => collections}/remove.kt |   5 +-
 .../util/{ => collections}/transpose.kt       |   8 +-
 .../util/{ => collections}/triples.kt         |   2 +-
 .../protocol/variant/QVariantList.kt          |   2 +-
 .../protocol/types/SignedIdProxy.java         |  36 +++
 .../protocol/util/collections/PairsProxy.java |  27 ++
 .../handshake/ClientInitAckSerializerTest.kt  | 286 +++++++++++++++++-
 .../ClientInitRejectSerializerTest.kt         | 104 +++++++
 .../handshake/ClientInitSerializerTest.kt     | 111 ++++++-
 .../handshake/ClientLoginAckSerializerTest.kt |  39 +++
 .../ClientLoginRejectSerializerTest.kt        | 105 +++++++
 .../handshake/ClientLoginSerializerTest.kt    |  92 ++++++
 .../handshake/CoreSetupAckSerializerTest.kt   |  39 +++
 .../handshake/CoreSetupDataSerializerTest.kt  | 205 +++++++++++++
 .../CoreSetupRejectSerializerTest.kt          | 104 +++++++
 .../handshake/SessionInitSerializerTest.kt    | 209 +++++++++++++
 .../serializers/qt/BoolSerializerTest.kt      |   2 +
 .../qt/ByteBufferSerializerTest.kt            |   2 +
 .../serializers/qt/ByteSerializerTest.kt      |   2 +
 .../serializers/qt/DoubleSerializerTest.kt    |   2 +
 .../serializers/qt/FloatSerializerTest.kt     |   2 +
 .../qt/HandshakeMapSerializerTest.kt          |   2 +
 .../serializers/qt/IntSerializerTest.kt       |   2 +
 .../serializers/qt/LongSerializerTest.kt      |   2 +
 .../serializers/qt/QCharSerializerTest.kt     |   2 +
 .../serializers/qt/QDateSerializerTest.kt     |   2 +
 .../serializers/qt/QDateTimeSerializerTest.kt |   2 +
 .../serializers/qt/QTimeSerializerTest.kt     |   2 +
 .../qt/QVariantListSerializerTest.kt          |   2 +
 .../qt/QVariantMapSerializerTest.kt           | 108 +------
 .../serializers/qt/QVariantSerializerTest.kt  |   2 +
 .../serializers/qt/ShortSerializerTest.kt     |   2 +
 .../serializers/qt/StringSerializerTest.kt    |   9 +
 .../serializers/qt/UByteSerializerTest.kt     |   2 +
 .../serializers/qt/UIntSerializerTest.kt      |   2 +
 .../serializers/qt/ULongSerializerTest.kt     |   2 +
 .../serializers/qt/UShortSerializerTest.kt    |   2 +
 .../serializers/qt/UuidSerializerTest.kt      |  47 +++
 .../serializers/qt/VoidSerializerTest.kt      |   2 +
 .../quassel/BufferIdSerializerTest.kt         |   2 +
 .../quassel/BufferInfoSerializerTest.kt       |   2 +
 .../DccIpDetectionModeSerializerTest.kt       |   2 +
 .../DccPortSelectionModeSerializerTest.kt     |   2 +
 .../quassel/IdentityIdSerializerTest.kt       |   2 +
 .../quassel/IrcChannelSerializerTest.kt       |  84 +++++
 .../quassel/IrcUserSerializerTest.kt          | 110 +++++++
 .../quassel/MessageSerializerTest.kt          |   2 +
 .../quassel/MsgIdSerializerTest.kt            |   2 +
 .../quassel/NetworkIdSerializerTest.kt        |   2 +
 .../quassel/NetworkInfoSerializerTest.kt      | 130 ++++++++
 .../quassel/PeerPtrSerializerTest.kt          |   2 +
 .../quassel/QHostAddressSerializerTest.kt     |   2 +
 .../HeartBeatReplySerializerTest.kt           |  69 +++++
 .../signalproxy/HeartBeatSerializerTest.kt    |  69 +++++
 .../signalproxy/InitDataSerializerTest.kt     | 183 +++++++++++
 .../signalproxy/InitRequestSerializerTest.kt  |  74 +++++
 .../signalproxy/RpcSerializerTest.kt          |  90 ++++++
 .../signalproxy/SyncSerializerTest.kt         | 187 ++++++++++++
 .../protocol/syncables/NetworkTest.kt         | 104 +++++++
 .../libquassel/protocol/testutil/Random.kt    |  75 +++++
 .../testutil/handshakeSerializerTest.kt       |  12 +-
 .../testutil/signalProxySerializerTest.kt     |  13 +-
 .../testutil/testPrimitiveSerializerDirect.kt |   1 -
 .../libquassel/protocol/types/SignedIdTest.kt |  88 ++++++
 .../protocol/util/collections/InsertTest.kt   |  66 ++++
 .../protocol/util/collections/MoveTest.kt     |  55 ++++
 .../protocol/util/collections/PairsTest.kt    |  54 ++++
 .../protocol/util/collections/RemoveTest.kt   |  28 ++
 .../protocol/util/expansion/ExpansionTest.kt  |   2 +-
 .../util/expression/ExpressionMatchTest.kt    |  12 -
 119 files changed, 3442 insertions(+), 563 deletions(-)
 create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
 create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
 create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
 create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
 create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/indices.kt (86%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{plus.kt => collections/insert.kt} (78%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/move.kt (55%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/pairs.kt (87%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/remove.kt (67%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/transpose.kt (64%)
 rename libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/{ => collections}/triples.kt (94%)
 create mode 100644 libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/types/SignedIdProxy.java
 create mode 100644 libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/util/collections/PairsProxy.java
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitRejectSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginAckSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginRejectSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupAckSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupRejectSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UuidSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializerTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/InsertTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/PairsTest.kt
 create mode 100644 libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/RemoveTest.kt

diff --git a/buildSrc/src/main/kotlin/de/justjanne/coverageconverter/CoverageConverterPlugin.kt b/buildSrc/src/main/kotlin/de/justjanne/coverageconverter/CoverageConverterPlugin.kt
index db06c80..c3d76ef 100644
--- a/buildSrc/src/main/kotlin/de/justjanne/coverageconverter/CoverageConverterPlugin.kt
+++ b/buildSrc/src/main/kotlin/de/justjanne/coverageconverter/CoverageConverterPlugin.kt
@@ -10,7 +10,6 @@
 
 package de.justjanne.coverageconverter
 
-import groovy.util.XmlSlurper
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
@@ -36,7 +35,7 @@ class CoverageConverterPlugin : Plugin<Project> {
         jacocoReportTask.dependsOn(testTask)
         if (extension.autoConfigureCoverage) {
           jacocoReportTask.sourceDirectories.from(fileTree("src/main/kotlin"))
-          jacocoReportTask.classDirectories.from(fileTree("build/classes"))
+          jacocoReportTask.classDirectories.from(fileTree("build/classes/kotlin/main"))
           jacocoReportTask.reports {
             xml.destination = File("${buildDir}/reports/jacoco/report.xml")
             html.isEnabled = true
diff --git a/libquassel-protocol/build.gradle.kts b/libquassel-protocol/build.gradle.kts
index 530c483..47844ec 100644
--- a/libquassel-protocol/build.gradle.kts
+++ b/libquassel-protocol/build.gradle.kts
@@ -9,6 +9,7 @@
  */
 
 plugins {
+  id("java-library")
   id("com.vanniktech.maven.publish")
   id("com.google.devtools.ksp") version "1.4.30-1.0.0-alpha02"
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/ByteBufferUtil.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/ByteBufferUtil.kt
index 0e871f9..93d977d 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/ByteBufferUtil.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/ByteBufferUtil.kt
@@ -64,15 +64,15 @@ private val alphabet = charArrayOf(
 fun ByteBuffer.contentToString(): String {
   val position = position()
   val limit = limit()
-  var result = ""
+  val result = StringBuilder()
   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]
+    result.append(alphabet[(upperNibble + 16) % 16])
+    result.append(alphabet[(lowerNibble + 16) % 16])
   }
   limit(limit)
   position(position)
-  return result
+  return result.toString()
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BackendInfoSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BackendInfoSerializer.kt
index 7198339..23d3086 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BackendInfoSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BackendInfoSerializer.kt
@@ -11,7 +11,7 @@
 package de.justjanne.libquassel.protocol.models
 
 import de.justjanne.libquassel.protocol.models.types.QtType
-import de.justjanne.libquassel.protocol.util.triples
+import de.justjanne.libquassel.protocol.util.collections.triples
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
index 2f44ba1..b6a3cf1 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/HandshakeMessage.kt
@@ -151,7 +151,7 @@ sealed class HandshakeMessage {
     /**
      * Storage backend configuration data
      */
-    val setupData: QVariantMap?,
+    val setupData: QVariantMap,
     /**
      * Chosen authenticator backend id
      */
@@ -159,7 +159,7 @@ sealed class HandshakeMessage {
     /**
      * Authenticator backend configuration data
      */
-    val authSetupData: QVariantMap?
+    val authSetupData: QVariantMap
   ) : HandshakeMessage()
 
   /**
@@ -184,7 +184,7 @@ sealed class HandshakeMessage {
      * Identity objects created or modified after [SessionInit] will be defined
      * via sync updates and RPC identity creation messages.
      */
-    val identities: QVariantList?,
+    val identities: List<QVariantMap>,
     /**
      * List of existing buffers at the current time.
      *
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkInfo.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkInfo.kt
index ce580bb..efdda29 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkInfo.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/NetworkInfo.kt
@@ -14,29 +14,29 @@ import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
 
 data class NetworkInfo(
-  var networkId: NetworkId = NetworkId(-1),
-  var networkName: String = "",
-  var identity: IdentityId = IdentityId(-1),
-  var useCustomEncodings: Boolean = false,
-  var codecForServer: String = "UTF_8",
-  var codecForEncoding: String = "UTF_8",
-  var codecForDecoding: String = "UTF_8",
-  var serverList: List<NetworkServer> = emptyList(),
-  var useRandomServer: Boolean = false,
-  var perform: List<String> = emptyList(),
-  var useAutoIdentify: Boolean = false,
-  var autoIdentifyService: String = "",
-  var autoIdentifyPassword: String = "",
-  var useSasl: Boolean = false,
-  var saslAccount: String = "",
-  var saslPassword: String = "",
-  var useAutoReconnect: Boolean = true,
-  var autoReconnectInterval: UInt = 0u,
-  var autoReconnectRetries: UShort = 0u,
-  var unlimitedReconnectRetries: Boolean = true,
-  var rejoinChannels: Boolean = true,
-  var useCustomMessageRate: Boolean = false,
-  var messageRateBurstSize: UInt = 0u,
-  var messageRateDelay: UInt = 0u,
-  var unlimitedMessageRate: Boolean = false
+  val networkId: NetworkId = NetworkId(-1),
+  val networkName: String = "",
+  val identity: IdentityId = IdentityId(-1),
+  val useCustomEncodings: Boolean = false,
+  val codecForServer: String = "UTF_8",
+  val codecForEncoding: String = "UTF_8",
+  val codecForDecoding: String = "UTF_8",
+  val serverList: List<NetworkServer> = emptyList(),
+  val useRandomServer: Boolean = false,
+  val perform: List<String> = emptyList(),
+  val useAutoIdentify: Boolean = false,
+  val autoIdentifyService: String = "",
+  val autoIdentifyPassword: String = "",
+  val useSasl: Boolean = false,
+  val saslAccount: String = "",
+  val saslPassword: String = "",
+  val useAutoReconnect: Boolean = true,
+  val autoReconnectInterval: UInt = 0u,
+  val autoReconnectRetries: UShort = 0u,
+  val unlimitedReconnectRetries: Boolean = true,
+  val rejoinChannels: Boolean = true,
+  val useCustomMessageRate: Boolean = false,
+  val messageRateBurstSize: UInt = 0u,
+  val messageRateDelay: UInt = 0u,
+  val unlimitedMessageRate: Boolean = false
 )
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/ids/SignedId.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/ids/SignedId.kt
index c3f53af..1b25a64 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/ids/SignedId.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/ids/SignedId.kt
@@ -42,7 +42,6 @@ interface SignedId<T> : Serializable, Comparable<SignedId<T>>
  */
 @Suppress("NOTHING_TO_INLINE")
 @JvmName("isValidId")
-@Generated
 inline fun SignedId<SignedIdType>.isValid() = id > 0
 
 /**
@@ -50,5 +49,4 @@ inline fun SignedId<SignedIdType>.isValid() = id > 0
  */
 @Suppress("NOTHING_TO_INLINE")
 @JvmName("isValidId64")
-@Generated
 inline fun SignedId<SignedId64Type>.isValid() = id > 0
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 b91ed38..f34a91e 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
@@ -17,6 +17,9 @@ import de.justjanne.libquassel.protocol.serializers.quassel.BufferInfoSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.DccIpDetectionModeSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.DccPortSelectionModeSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.IdentityIdSerializer
+import de.justjanne.libquassel.protocol.serializers.quassel.IdentitySerializer
+import de.justjanne.libquassel.protocol.serializers.quassel.IrcChannelSerializer
+import de.justjanne.libquassel.protocol.serializers.quassel.IrcUserSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.MessageSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.MsgIdSerializer
 import de.justjanne.libquassel.protocol.serializers.quassel.NetworkIdSerializer
@@ -70,19 +73,19 @@ enum class QuasselType(
    * Type for IrcUser objects
    * Serialized as [de.justjanne.libquassel.protocol.variant.QVariantMap]
    */
-  IrcUser("IrcUser"),
+  IrcUser("IrcUser", IrcUserSerializer),
 
   /**
    * Type for IrcChannel objects
    * Serialized as [de.justjanne.libquassel.protocol.variant.QVariantMap]
    */
-  IrcChannel("IrcChannel"),
+  IrcChannel("IrcChannel", IrcChannelSerializer),
 
   /**
    * Type for Identity objects
    * Serialized as [de.justjanne.libquassel.protocol.variant.QVariantMap]
    */
-  Identity("Identity"),
+  Identity("Identity", IdentitySerializer),
 
   /**
    * Type for [de.justjanne.libquassel.protocol.models.IdentityId]
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
index 9b3d190..5727ff1 100644
--- 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
@@ -47,7 +47,7 @@ object SignalProxyMessageSerializer : PrimitiveSerializer<SignalProxyMessage> {
     }
 
   private fun deserializeFromList(data: QVariantList): SignalProxyMessage =
-    when (val type = data.firstOrNull().into<Int>(0)) {
+    when (val type = data.firstOrNull().into(0)) {
       SyncSerializer.type ->
         SyncSerializer.deserialize(data)
       RpcSerializer.type ->
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializer.kt
index a466dc9..675587d 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializer.kt
@@ -39,14 +39,14 @@ object CoreSetupDataSerializer : HandshakeSerializer<HandshakeMessage.CoreSetupD
   )
 
   override fun deserialize(data: QVariantMap) =
-    data["SetupData"].into<QVariantMap>().let {
+    data["SetupData"].into<QVariantMap>().orEmpty().let {
       HandshakeMessage.CoreSetupData(
-        adminUser = it?.get("AdminUser").into(),
-        adminPassword = it?.get("AdminPasswd").into(),
-        backend = it?.get("Backend").into(),
-        setupData = it?.get("ConnectionProperties").into(),
-        authenticator = it?.get("Authenticator").into(),
-        authSetupData = it?.get("AuthProperties").into()
+        adminUser = it["AdminUser"].into(),
+        adminPassword = it["AdminPasswd"].into(),
+        backend = it["Backend"].into(),
+        setupData = it["ConnectionProperties"].into<QVariantMap>().orEmpty(),
+        authenticator = it["Authenticator"].into(),
+        authSetupData = it["AuthProperties"].into<QVariantMap>().orEmpty()
       )
     }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
index 4e55b55..3bde603 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializer.kt
@@ -18,6 +18,7 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.serializers.HandshakeSerializer
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
 
@@ -27,23 +28,25 @@ import de.justjanne.libquassel.protocol.variant.qVariant
 object SessionInitSerializer : HandshakeSerializer<HandshakeMessage.SessionInit> {
   override val type: String = "SessionInit"
 
-  override fun serialize(data: HandshakeMessage.SessionInit) = mapOf(
-    "MsgType" to qVariant(type, QtType.QString),
-    "SessionState" to qVariant(
+  override fun serialize(data: HandshakeMessage.SessionInit) = mapOf<String, QVariant_>(
+    "MsgType" to qVariant<String>(type, QtType.QString),
+    "SessionState" to qVariant<QVariantMap>(
       mapOf(
         "BufferInfos" to qVariant<QVariantList>(
           data.bufferInfos.map {
-            qVariant(it, QuasselType.BufferInfo)
+            qVariant<BufferInfo>(it, QuasselType.BufferInfo)
           },
           QtType.QVariantList
         ),
         "NetworkIds" to qVariant<QVariantList>(
           data.networkIds.map {
-            qVariant(it, QuasselType.NetworkId)
+            qVariant<NetworkId>(it, QuasselType.NetworkId)
           },
           QtType.QVariantList
         ),
-        "Identities" to qVariant(data.identities, QtType.QVariantList),
+        "Identities" to qVariant<QVariantList>(data.identities.map {
+          qVariant<QVariantMap>(it, QuasselType.Identity)
+        }, QtType.QVariantList),
       ),
       QtType.QVariantMap
     )
@@ -57,7 +60,9 @@ object SessionInitSerializer : HandshakeSerializer<HandshakeMessage.SessionInit>
       networkIds = it?.get("NetworkIds").into<QVariantList>()?.mapNotNull {
         it.into<NetworkId>()
       }.orEmpty(),
-      identities = it?.get("Identities").into(),
+      identities = it?.get("Identities").into<QVariantList>()?.mapNotNull {
+        it.into<QVariantMap>()
+      }.orEmpty(),
     )
   }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializer.kt
index ce918fe..0394c64 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializer.kt
@@ -12,6 +12,7 @@ package de.justjanne.libquassel.protocol.serializers.qt
 
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.io.contentToString
 import de.justjanne.libquassel.protocol.io.copyData
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
 import java.nio.ByteBuffer
@@ -27,6 +28,7 @@ object ByteBufferSerializer : PrimitiveSerializer<ByteBuffer?> {
     if (data != null) {
       buffer.put(data)
     }
+    data?.rewind()
   }
 
   override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): ByteBuffer? {
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializer.kt
index 0756ab3..57a0b02 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializer.kt
@@ -33,6 +33,12 @@ object QVariantSerializer : PrimitiveSerializer<QVariant_> {
         BoolSerializer.serialize(buffer, false, featureSet)
         data.serialize(buffer, featureSet)
       }
+      is QVariant.Custom -> {
+        IntSerializer.serialize(buffer, QtType.UserType.id, featureSet)
+        BoolSerializer.serialize(buffer, false, featureSet)
+        StringSerializerAscii.serialize(buffer, data.type.typeName, featureSet)
+        data.serialize(buffer, featureSet)
+      }
     }
   }
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializer.kt
index 9857ba7..e21f8a5 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializer.kt
@@ -14,6 +14,7 @@ import de.justjanne.bitflags.of
 import de.justjanne.bitflags.toBits
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.io.contentToString
 import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.flags.BufferType
 import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
new file mode 100644
index 0000000..4ee18fc
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentitySerializer.kt
@@ -0,0 +1,34 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.serializers.quassel
+
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
+import de.justjanne.libquassel.protocol.serializers.qt.QVariantMapSerializer
+import de.justjanne.libquassel.protocol.syncables.Identity
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import java.nio.ByteBuffer
+
+/**
+ * Serializer for [QVariantMap], with custom name for [Identity]
+ */
+object IdentitySerializer : PrimitiveSerializer<QVariantMap> {
+
+  @Suppress("UNCHECKED_CAST")
+  override val javaType: Class<out QVariantMap> = Map::class.java as Class<QVariantMap>
+
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, featureSet: FeatureSet) =
+    QVariantMapSerializer.serialize(buffer, data, featureSet)
+
+  override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): QVariantMap =
+    QVariantMapSerializer.deserialize(buffer, featureSet)
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
new file mode 100644
index 0000000..45f2d51
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializer.kt
@@ -0,0 +1,34 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.serializers.quassel
+
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
+import de.justjanne.libquassel.protocol.serializers.qt.QVariantMapSerializer
+import de.justjanne.libquassel.protocol.syncables.IrcChannel
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import java.nio.ByteBuffer
+
+/**
+ * Serializer for [QVariantMap], with custom name for [IrcChannel]
+ */
+object IrcChannelSerializer : PrimitiveSerializer<QVariantMap> {
+
+  @Suppress("UNCHECKED_CAST")
+  override val javaType: Class<out QVariantMap> = Map::class.java as Class<QVariantMap>
+
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, featureSet: FeatureSet) =
+    QVariantMapSerializer.serialize(buffer, data, featureSet)
+
+  override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): QVariantMap =
+    QVariantMapSerializer.deserialize(buffer, featureSet)
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
new file mode 100644
index 0000000..1e4c31c
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializer.kt
@@ -0,0 +1,34 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.serializers.quassel
+
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.serializers.PrimitiveSerializer
+import de.justjanne.libquassel.protocol.serializers.qt.QVariantMapSerializer
+import de.justjanne.libquassel.protocol.syncables.IrcUser
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import java.nio.ByteBuffer
+
+/**
+ * Serializer for [QVariantMap], with custom name for [IrcUser]
+ */
+object IrcUserSerializer : PrimitiveSerializer<QVariantMap> {
+
+  @Suppress("UNCHECKED_CAST")
+  override val javaType: Class<out QVariantMap> = Map::class.java as Class<QVariantMap>
+
+  override fun serialize(buffer: ChainedByteBuffer, data: QVariantMap, featureSet: FeatureSet) =
+    QVariantMapSerializer.serialize(buffer, data, featureSet)
+
+  override fun deserialize(buffer: ByteBuffer, featureSet: FeatureSet): QVariantMap =
+    QVariantMapSerializer.deserialize(buffer, featureSet)
+}
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
index 3b486d5..b354c39 100644
--- 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
@@ -30,6 +30,6 @@ object HeartBeatReplySerializer : SignalProxySerializer<SignalProxyMessage.Heart
   )
 
   override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeatReply(
-    data[1].into(Instant.EPOCH)
+    data.getOrNull(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
index 07576f6..9bbe2a7 100644
--- 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
@@ -30,6 +30,6 @@ object HeartBeatSerializer : SignalProxySerializer<SignalProxyMessage.HeartBeat>
   )
 
   override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeat(
-    data[1].into(Instant.EPOCH)
+    data.getOrNull(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
index 33e7b77..c8799c2 100644
--- 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
@@ -34,8 +34,8 @@ object InitDataSerializer : SignalProxySerializer<SignalProxyMessage.InitData> {
   ) + data.initData.toVariantList()
 
   override fun deserialize(data: QVariantList) = SignalProxyMessage.InitData(
-    StringSerializerUtf8.deserializeRaw(data[1].into<ByteBuffer>()),
-    StringSerializerUtf8.deserializeRaw(data[2].into<ByteBuffer>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(1).into<ByteBuffer>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(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
index d31ad07..41972b2 100644
--- 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
@@ -26,13 +26,13 @@ object InitRequestSerializer : SignalProxySerializer<SignalProxyMessage.InitRequ
   override val type: Int = 3
 
   override fun serialize(data: SignalProxyMessage.InitRequest) = listOf(
-    qVariant(InitDataSerializer.type, QtType.Int),
+    qVariant(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>())
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(1).into<ByteBuffer>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(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
index 8b44ffc..45624f4 100644
--- 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
@@ -26,12 +26,12 @@ object RpcSerializer : SignalProxySerializer<SignalProxyMessage.Rpc> {
   override val type: Int = 2
 
   override fun serialize(data: SignalProxyMessage.Rpc) = listOf(
-    qVariant(SyncSerializer.type, QtType.Int),
+    qVariant(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>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(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
index a1038fa..f5a7e3e 100644
--- 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
@@ -33,9 +33,9 @@ object SyncSerializer : SignalProxySerializer<SignalProxyMessage.Sync> {
   ) + 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>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(1).into<ByteBuffer>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(2).into<ByteBuffer>()),
+    StringSerializerUtf8.deserializeRaw(data.getOrNull(3).into<ByteBuffer>()),
     data.drop(4)
   )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/AliasManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/AliasManager.kt
index 8b1e1fd..957bb11 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/AliasManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/AliasManager.kt
@@ -21,11 +21,12 @@ import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class AliasManager(
-  session: Session
-) : SyncableObject(session, "AliasManager"), AliasManagerStub {
+  session: Session? = null,
+  state: AliasManagerState = AliasManagerState()
+) : StatefulSyncableObject<AliasManagerState>(session, "AliasManager", state),
+  AliasManagerStub {
   override fun toVariantMap(): QVariantMap = mapOf(
     "Aliases" to qVariant(
       mapOf(
@@ -72,7 +73,7 @@ open class AliasManager(
     message: String
   ) = state().processInput(
     info,
-    session.network(info.networkId)?.state(),
+    session?.network(info.networkId)?.state(),
     message
   )
 
@@ -82,7 +83,7 @@ open class AliasManager(
     previousCommands: MutableList<Command>
   ) = state().processInput(
     info,
-    session.network(info.networkId)?.state(),
+    session?.network(info.networkId)?.state(),
     message,
     previousCommands
   )
@@ -95,19 +96,8 @@ open class AliasManager(
   ) = state().expand(
     expansion,
     bufferInfo,
-    session.network(bufferInfo.networkId)?.state(),
+    session?.network(bufferInfo.networkId)?.state(),
     arguments,
     previousCommands
   )
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    AliasManagerState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BacklogManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BacklogManager.kt
index d6a15b6..cea6cd1 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BacklogManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BacklogManager.kt
@@ -15,7 +15,7 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
 
 open class BacklogManager(
-  session: Session
+  session: Session? = null
 ) : SyncableObject(session, "BacklogManager"), BacklogManagerStub {
 
   override fun fromVariantMap(properties: QVariantMap) = Unit
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferSyncer.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferSyncer.kt
index ae81bcb..37d4cd3 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferSyncer.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferSyncer.kt
@@ -23,17 +23,18 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.syncables.state.BufferSyncerState
 import de.justjanne.libquassel.protocol.syncables.stubs.BufferSyncerStub
-import de.justjanne.libquassel.protocol.util.pairs
+import de.justjanne.libquassel.protocol.util.collections.pairs
 import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class BufferSyncer(
-  session: Session
-) : SyncableObject(session, "BufferSyncer"), BufferSyncerStub {
+  session: Session? = null,
+  state: BufferSyncerState = BufferSyncerState()
+) : StatefulSyncableObject<BufferSyncerState>(session, "BufferSyncer", state),
+  BufferSyncerStub {
   override fun toVariantMap() = mapOf(
     "Activities" to qVariant(
       state().activities.flatMap { (key, value) ->
@@ -178,7 +179,7 @@ open class BufferSyncer(
       val bufferInfo = bufferInfo(buffer)
 
       if (bufferInfo != null) {
-        session.bufferViewManager().handleBuffer(bufferInfo, true)
+        session?.bufferViewManager()?.handleBuffer(bufferInfo, true)
       }
     }
 
@@ -200,19 +201,8 @@ open class BufferSyncer(
       }
 
       if (oldInfo != null) {
-        session.bufferViewManager().handleBuffer(info)
+        session?.bufferViewManager()?.handleBuffer(info)
       }
     }
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    BufferSyncerState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
index 583f119..a246f65 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
@@ -21,19 +21,19 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
 import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewConfigStub
-import de.justjanne.libquassel.protocol.util.insert
-import de.justjanne.libquassel.protocol.util.move
+import de.justjanne.libquassel.protocol.util.collections.insert
+import de.justjanne.libquassel.protocol.util.collections.move
 import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class BufferViewConfig(
-  bufferViewId: Int,
-  session: Session
-) : SyncableObject(session, "BufferViewConfig"), BufferViewConfigStub {
+  session: Session? = null,
+  state: BufferViewConfigState
+) : StatefulSyncableObject<BufferViewConfigState>(session, "BufferViewConfig", state),
+  BufferViewConfigStub {
   override fun fromVariantMap(properties: QVariantMap) {
     state.update {
       copy(
@@ -236,9 +236,14 @@ open class BufferViewConfig(
       info.bufferId,
       buffers()
         .asSequence()
-        .map(session.bufferSyncer()::bufferInfo)
         .withIndex()
-        .mapNotNull { (index, value) -> IndexedValue(index, value ?: return@mapNotNull null) }
+        .mapNotNull { (index, value) ->
+          IndexedValue(
+            index,
+            session?.bufferSyncer()?.bufferInfo(value)
+              ?: return@mapNotNull null
+          )
+        }
         .filter { (_, value) -> value.networkId == info.networkId }
         .find { (_, value) ->
           String.CASE_INSENSITIVE_ORDER.compare(value.bufferName, info.bufferName) > 0
@@ -261,17 +266,4 @@ open class BufferViewConfig(
       insertBufferSorted(info)
     }
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    BufferViewConfigState(
-      bufferViewId = bufferViewId
-    )
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManager.kt
index dde3434..07f1b48 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManager.kt
@@ -12,6 +12,7 @@ package de.justjanne.libquassel.protocol.syncables
 
 import de.justjanne.libquassel.protocol.models.BufferInfo
 import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
 import de.justjanne.libquassel.protocol.syncables.state.BufferViewManagerState
 import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewManagerStub
 import de.justjanne.libquassel.protocol.util.update
@@ -20,11 +21,12 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class BufferViewManager(
-  session: Session
-) : SyncableObject(session, "BufferViewManager"), BufferViewManagerStub {
+  session: Session? = null,
+  state: BufferViewManagerState = BufferViewManagerState()
+) : StatefulSyncableObject<BufferViewManagerState>(session, "BufferViewManager", state),
+  BufferViewManagerStub {
   override fun fromVariantMap(properties: QVariantMap) {
     properties["BufferViewIds"].into<QVariantList>()
       ?.mapNotNull<QVariant_, Int>(QVariant_::into)
@@ -49,8 +51,12 @@ open class BufferViewManager(
       return
     }
 
-    val config = BufferViewConfig(bufferViewConfigId, session)
-    session.synchronize(config)
+    val config = BufferViewConfig(
+      session, BufferViewConfigState(
+        bufferViewId = bufferViewConfigId
+      )
+    )
+    session?.synchronize(config)
     state.update {
       copy(bufferViewConfigs = bufferViewConfigs + Pair(bufferViewConfigId, config))
     }
@@ -63,15 +69,4 @@ open class BufferViewManager(
       bufferViewConfig.handleBuffer(info, unhide)
     }
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    BufferViewManagerState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CertManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CertManager.kt
index a420f96..1021105 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CertManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CertManager.kt
@@ -10,7 +10,6 @@
 
 package de.justjanne.libquassel.protocol.syncables
 
-import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8
 import de.justjanne.libquassel.protocol.syncables.state.CertManagerState
@@ -19,7 +18,6 @@ import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 import org.bouncycastle.cert.X509CertificateHolder
 import org.bouncycastle.openssl.PEMKeyPair
 import org.bouncycastle.openssl.PEMParser
@@ -30,9 +28,10 @@ import java.security.cert.Certificate
 import java.security.cert.CertificateFactory
 
 open class CertManager(
-  identityId: IdentityId,
-  session: Session
-) : SyncableObject(session, "CertManager"), CertManagerStub {
+  session: Session? = null,
+  state: CertManagerState
+) : StatefulSyncableObject<CertManagerState>(session, "CertManager", state),
+  CertManagerStub {
   override fun fromVariantMap(properties: QVariantMap) {
     val privateKeyPem = properties["sslKey"].into("")
     val certPem = properties["sslCert"].into("")
@@ -110,17 +109,4 @@ open class CertManager(
 
   fun certificate() = state().certificate
   fun certificatePem() = state().certificatePem
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    CertManagerState(
-      identityId = identityId
-    )
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CoreInfo.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CoreInfo.kt
index d78c7e3..521179d 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CoreInfo.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/CoreInfo.kt
@@ -20,12 +20,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 import org.threeten.bp.Instant
 
 open class CoreInfo(
-  session: Session
-) : SyncableObject(session, "CoreInfo"), CoreInfoStub {
+  session: Session? = null,
+  state: CoreInfoState = CoreInfoState()
+) : StatefulSyncableObject<CoreInfoState>(session, "CoreInfo", state),
+  CoreInfoStub {
   override fun fromVariantMap(properties: QVariantMap) {
     val coreData = properties["coreData"].into<QVariantMap>().orEmpty()
 
@@ -68,15 +69,4 @@ open class CoreInfo(
     fromVariantMap(data)
     super.setCoreData(data)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    CoreInfoState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/DccConfig.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/DccConfig.kt
index b199aa0..0127d7c 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/DccConfig.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/DccConfig.kt
@@ -20,13 +20,14 @@ import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 import java.net.InetAddress
 
 open class DccConfig(
-  session: Session
-) : SyncableObject(session, "DccConfig"), DccConfigStub {
-  override fun init() {
+  session: Session? = null,
+  state: DccConfigState = DccConfigState()
+) : StatefulSyncableObject<DccConfigState>(session, "DccConfig", state),
+  DccConfigStub {
+  init {
     renameObject("DccConfig")
   }
 
@@ -140,15 +141,4 @@ open class DccConfig(
   fun sendTimeout() = state().sendTimeout
   fun usePassiveDcc() = state().usePassiveDcc
   fun useFastSend() = state().useFastSend
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    DccConfigState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt
index cc24585..a5fac79 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt
@@ -21,11 +21,12 @@ import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class HighlightRuleManager(
-  session: Session
-) : SyncableObject(session, "HighlightRuleManager"), HighlightRuleManagerStub {
+  session: Session? = null,
+  state: HighlightRuleManagerState = HighlightRuleManagerState()
+) : StatefulSyncableObject<HighlightRuleManagerState>(session, "HighlightRuleManager", state),
+  HighlightRuleManagerStub {
   override fun fromVariantMap(properties: QVariantMap) {
     val highlightRules = properties["HighlightRuleList"].into<QVariantMap>().orEmpty()
 
@@ -200,15 +201,4 @@ open class HighlightRuleManager(
     }
     super.setNicksCaseSensitive(nicksCaseSensitive)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    HighlightRuleManagerState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Identity.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Identity.kt
index 6690de8..5b30051 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Identity.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Identity.kt
@@ -20,12 +20,13 @@ import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class Identity(
-  session: Session
-) : SyncableObject(session, "Identity"), IdentityStub {
-  override fun init() {
+  session: Session? = null,
+  state: IdentityState = IdentityState()
+) : StatefulSyncableObject<IdentityState>(session, "Identity", state),
+  IdentityStub {
+  init {
     renameObject(state().identifier())
   }
 
@@ -53,6 +54,7 @@ open class Identity(
         quitReason = properties["quitReason"].into(quitReason),
       )
     }
+    renameObject(state().identifier())
   }
 
   override fun toVariantMap() = mapOf(
@@ -229,15 +231,4 @@ open class Identity(
     }
     super.setRealName(realName)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    IdentityState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
new file mode 100644
index 0000000..c16ba3e
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
@@ -0,0 +1,12 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.syncables
+
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
index 210546c..22b55ce 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
@@ -13,7 +13,6 @@ package de.justjanne.libquassel.protocol.syncables
 import de.justjanne.libquassel.protocol.models.ChannelModeType
 import de.justjanne.libquassel.protocol.models.ChannelModes
 import de.justjanne.libquassel.protocol.models.QStringList
-import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
 import de.justjanne.libquassel.protocol.syncables.stubs.IrcChannelStub
@@ -22,14 +21,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.indexed
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class IrcChannel(
-  name: String,
-  network: NetworkId,
-  session: Session
-) : SyncableObject(session, "IrcChannel"), IrcChannelStub {
-  override fun init() {
+  session: Session? = null,
+  state: IrcChannelState
+) : StatefulSyncableObject<IrcChannelState>(session, "IrcChannel", state),
+  IrcChannelStub {
+  init {
     require(name().isNotEmpty()) {
       "IrcChannel: channelName is empty"
     }
@@ -76,15 +74,15 @@ open class IrcChannel(
   fun topic() = state().topic
   fun password() = state().password
   fun isEncrypted() = state().encrypted
-  fun ircUsers() = state().ircUsers(session.network(network())?.state())
+  fun ircUsers() = state().ircUsers(session?.network(network())?.state())
 
   fun userCount() = state().userModes.size
   fun userModes(nick: String) = state().userModes[nick]
-  fun hasMode(mode: Char) = state().hasMode(session.network(network())?.state(), mode)
+  fun hasMode(mode: Char) = state().hasMode(session?.network(network())?.state(), mode)
 
-  fun modeValue(mode: Char) = state().modeValue(session.network(network())?.state(), mode)
+  fun modeValue(mode: Char) = state().modeValue(session?.network(network())?.state(), mode)
 
-  fun modeValues(mode: Char) = state().modeValues(session.network(network())?.state(), mode)
+  fun modeValues(mode: Char) = state().modeValues(session?.network(network())?.state(), mode)
 
   fun channelModeString() = state().channelModeString()
 
@@ -119,7 +117,7 @@ open class IrcChannel(
   }
 
   private fun joinIrcUsers(map: Map<String, Set<Char>>) {
-    val network = session.network(network())
+    val network = session?.network(network())
 
     val newNicks = map.keys - state().userModes.keys
     state.update {
@@ -143,7 +141,7 @@ open class IrcChannel(
   )
 
   override fun part(nick: String) {
-    val network = session.network(network())
+    val network = session?.network(network())
     val partingUser = network?.ircUser(nick)
 
     if (partingUser != null) {
@@ -156,7 +154,7 @@ open class IrcChannel(
           copy(channelModes = ChannelModes())
         }
         network.removeIrcChannel(this)
-        session.stopSynchronize(this)
+        session?.stopSynchronize(this)
       }
     }
     super.part(nick)
@@ -199,7 +197,7 @@ open class IrcChannel(
   }
 
   override fun addChannelMode(mode: Char, value: String?) {
-    val network = session.network(network())
+    val network = session?.network(network())
     state.update {
       copy(
         channelModes = channelModes.run {
@@ -236,7 +234,7 @@ open class IrcChannel(
   }
 
   override fun removeChannelMode(mode: Char, value: String?) {
-    val network = session.network(network())
+    val network = session?.network(network())
     state.update {
       copy(
         channelModes = channelModes.run {
@@ -263,18 +261,4 @@ open class IrcChannel(
     }
     super.removeChannelMode(mode, value)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    IrcChannelState(
-      network = network,
-      name = name
-    )
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcListHelper.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcListHelper.kt
index c997cb7..67f1fb3 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcListHelper.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcListHelper.kt
@@ -15,7 +15,7 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
 
 open class IrcListHelper(
-  session: Session
+  session: Session? = null
 ) : SyncableObject(session, "IrcListHelper"), IrcListHelperStub {
   override fun fromVariantMap(properties: QVariantMap) = Unit
   override fun toVariantMap() = emptyMap<String, QVariant_>()
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUser.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUser.kt
index 36b4fb2..514bf1c 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUser.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUser.kt
@@ -10,7 +10,6 @@
 
 package de.justjanne.libquassel.protocol.syncables
 
-import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.syncables.state.IrcUserState
 import de.justjanne.libquassel.protocol.syncables.stubs.IrcUserStub
@@ -20,20 +19,15 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.indexed
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 import org.threeten.bp.Instant
 import org.threeten.bp.temporal.Temporal
 
 open class IrcUser(
-  hostmask: String,
-  network: NetworkId,
-  session: Session
-) : SyncableObject(session, "IrcUser"), IrcUserStub {
-  override fun init() {
-    updateObjectName()
-  }
-
-  private fun updateObjectName() {
+  session: Session? = null,
+  state: IrcUserState
+) : StatefulSyncableObject<IrcUserState>(session, "IrcUser", state),
+  IrcUserStub {
+  init {
     renameObject(state().identifier())
   }
 
@@ -49,7 +43,7 @@ open class IrcUser(
         realName = properties["realName"].indexed(index).into(realName),
         account = properties["account"].indexed(index).into(account),
         away = properties["away"].indexed(index).into(away),
-        awayMessage = properties["user"].indexed(index).into(awayMessage),
+        awayMessage = properties["awayMessage"].indexed(index).into(awayMessage),
         idleTime = properties["idleTime"].indexed(index).into(idleTime),
         loginTime = properties["loginTime"].indexed(index).into(loginTime),
         server = properties["server"].indexed(index).into(server),
@@ -65,6 +59,7 @@ open class IrcUser(
         userModes = properties["userModes"].indexed(index).into(userModes),
       )
     }
+    renameObject(state().identifier())
   }
 
   override fun toVariantMap() = mapOf(
@@ -85,8 +80,8 @@ open class IrcUser(
     "suserHost" to qVariant(suserHost(), QtType.QString),
     "encrypted" to qVariant(encrypted(), QtType.Bool),
 
-    "channels" to qVariant(channels(), QtType.QStringList),
-    "userModes" to qVariant(userModes(), QtType.QString)
+    "channels" to qVariant(channels().toList(), QtType.QStringList),
+    "userModes" to qVariant(userModes().joinToString(), QtType.QString)
   )
 
   override fun updateHostmask(mask: String) {
@@ -126,12 +121,12 @@ open class IrcUser(
   }
 
   override fun setNick(nick: String) {
-    val network = session.network(network())
+    val network = session?.network(network())
     network?.ircUserNickChanged(nick(), nick)
     state.update {
       copy(nick = nick)
     }
-    updateObjectName()
+    renameObject(state().identifier())
     super.setNick(nick)
   }
 
@@ -248,13 +243,13 @@ open class IrcUser(
   }
 
   override fun joinChannel(channelname: String) {
-    val network = session.network(network()) ?: return
+    val network = session?.network(network()) ?: return
     val channel = network.newIrcChannel(channelname)
     joinChannel(channel)
   }
 
   fun partChannel(channel: IrcChannel) {
-    val network = session.network(network())
+    val network = session?.network(network())
 
     state.update {
       copy(channels = channels - channel.name())
@@ -267,7 +262,7 @@ open class IrcUser(
   }
 
   override fun quit() {
-    val network = session.network(network())
+    val network = session?.network(network())
     for (channel in channels()) {
       network?.ircChannel(channel)
         ?.part(nick())
@@ -276,7 +271,7 @@ open class IrcUser(
       copy(channels = emptySet())
     }
     network?.removeIrcUser(this)
-    session.stopSynchronize(this)
+    session?.stopSynchronize(this)
     super.quit()
   }
 
@@ -301,20 +296,4 @@ open class IrcUser(
   fun encrypted() = state().encrypted
   fun userModes() = state().userModes
   fun channels() = state().channels
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    IrcUserState(
-      network = network,
-      nick = HostmaskHelper.nick(hostmask),
-      user = HostmaskHelper.user(hostmask),
-      host = HostmaskHelper.host(hostmask)
-    )
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Network.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Network.kt
index 67a9bcc..5b00831 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Network.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/Network.kt
@@ -16,16 +16,17 @@ import de.justjanne.libquassel.protocol.models.NetworkInfo
 import de.justjanne.libquassel.protocol.models.NetworkServer
 import de.justjanne.libquassel.protocol.models.QStringList
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
-import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8
+import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
+import de.justjanne.libquassel.protocol.syncables.state.IrcUserState
 import de.justjanne.libquassel.protocol.syncables.state.NetworkState
 import de.justjanne.libquassel.protocol.syncables.stubs.NetworkStub
-import de.justjanne.libquassel.protocol.util.indices
+import de.justjanne.libquassel.protocol.util.collections.indices
 import de.justjanne.libquassel.protocol.util.irc.HostmaskHelper
 import de.justjanne.libquassel.protocol.util.irc.IrcISupport
-import de.justjanne.libquassel.protocol.util.transpose
+import de.justjanne.libquassel.protocol.util.collections.transpose
 import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -35,10 +36,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
 import java.nio.ByteBuffer
 
 open class Network(
-  networkId: NetworkId,
-  session: Session
-) : SyncableObject(session, "Network"), NetworkStub {
-  override fun init() {
+  session: Session? = null,
+  state: NetworkState
+) : StatefulSyncableObject<NetworkState>(session, "Network", state),
+  NetworkStub {
+  init {
     renameObject(state().identifier())
   }
 
@@ -95,7 +97,7 @@ open class Network(
           .into(useCustomMessageRate),
         messageRateBurstSize = properties["msgRateBurstSize"]
           .into(messageRateBurstSize),
-        messageRateDelay = properties["messageRateDelay"]
+        messageRateDelay = properties["msgRateMessageDelay"]
           .into(messageRateDelay),
         unlimitedMessageRate = properties["unlimitedMessageRate"]
           .into(unlimitedMessageRate),
@@ -119,47 +121,24 @@ open class Network(
           .orEmpty(),
         ircUsers = properties["IrcUsersAndChannels"].into<QVariantMap>()
           ?.get("Users")?.into<QVariantMap>()
-          ?.let {
-            it.indices.map { index ->
-              newIrcUser(
-                properties["nick"]
-                  .into<QVariantList>()
-                  ?.getOrNull(index)
-                  .into(""),
-                properties,
-                index
-              )
+          ?.let { user ->
+            user["nick"].into<QVariantList>()?.withIndex()?.map { (index, value) ->
+              newIrcUser(value.into(""), user, index)
             }
           }
           ?.associateBy { caseMapper().toLowerCase(it.nick()) }
           .orEmpty(),
         ircChannels = properties["IrcUsersAndChannels"].into<QVariantMap>()
           ?.get("Channels")?.into<QVariantMap>()
-          ?.let {
-            it.indices.map { index ->
-              newIrcChannel(
-                properties["name"]
-                  .into<QVariantList>()
-                  ?.getOrNull(index)
-                  .into(""),
-                properties,
-                index
-              )
+          ?.let { channel ->
+            channel["name"].into<QVariantList>()?.withIndex()?.map { (index, value) ->
+              newIrcChannel(value.into(""), channel, index)
             }
           }
           ?.associateBy { caseMapper().toLowerCase(it.name()) }
           .orEmpty()
       )
     }
-    state.update {
-      val (prefixes, prefixModes) = determinePrefixes()
-      val channelModeTypes = determineChannelModeTypes()
-      copy(
-        prefixes = prefixes,
-        prefixModes = prefixModes,
-        channelModes = channelModeTypes
-      )
-    }
   }
 
   override fun toVariantMap() = mapOf(
@@ -199,6 +178,7 @@ open class Network(
     "msgRateBurstSize" to qVariant(messageRateBurstSize(), QtType.UInt),
     "msgRateMessageDelay" to qVariant(messageRateDelay(), QtType.UInt),
     "unlimitedMessageRate" to qVariant(unlimitedMessageRate(), QtType.Bool),
+    "skipCaps" to qVariant(skipCaps().toList(), QtType.QStringList),
     "Supports" to qVariant(
       supports().mapValues { (_, value) -> qVariant(value, QtType.QString) },
       QtType.QVariantMap
@@ -335,21 +315,27 @@ open class Network(
     properties: QVariantMap = emptyMap(),
     index: Int? = null
   ): IrcUser {
-    val nick = caseMapper().toLowerCase(HostmaskHelper.nick(hostMask))
+    val (nick, ident, host) = HostmaskHelper.split(hostMask)
     val ircUser = ircUser(nick)
     if (ircUser != null) {
       return ircUser
     }
 
-    val user = IrcUser(hostMask, networkId(), session)
-    user.init()
+    val user = IrcUser(
+      session, IrcUserState(
+        network = networkId(),
+        nick = nick,
+        user = ident,
+        host = host
+      )
+    )
     if (properties.isNotEmpty()) {
       user.fromVariantMap(properties, index)
       user.initialized = true
     }
-    session.synchronize(user)
+    session?.synchronize(user)
     state.update {
-      copy(ircUsers = ircUsers + Pair(nick, user))
+      copy(ircUsers = ircUsers + Pair(caseMapper().toLowerCase(nick), user))
     }
     return user
   }
@@ -364,12 +350,16 @@ open class Network(
       return ircChannel
     }
 
-    val channel = IrcChannel(name, networkId(), session)
-    channel.init()
+    val channel = IrcChannel(
+      session, IrcChannelState(
+        network = networkId(),
+        name = name
+      )
+    )
     if (properties.isNotEmpty()) {
       channel.fromVariantMap(properties, index)
       channel.initialized = true
-      session.synchronize(channel)
+      session?.synchronize(channel)
       state.update {
         copy(ircChannels = ircChannels + Pair(caseMapper().toLowerCase(name), channel))
       }
@@ -464,49 +454,6 @@ open class Network(
     }
   }
 
-  private fun determineChannelModeTypes(): Map<ChannelModeType, Set<Char>> {
-    return ChannelModeType.values()
-      .zip(
-        supportValue(IrcISupport.CHANMODES)
-          ?.split(',', limit = ChannelModeType.values().size)
-          ?.map(String::toSet)
-          .orEmpty()
-      )
-      .toMap()
-  }
-
-  private fun determinePrefixes(): Pair<List<Char>, List<Char>> {
-    val defaultPrefixes = listOf('~', '&', '@', '%', '+')
-    val defaultPrefixModes = listOf('q', 'a', 'o', 'h', 'v')
-
-    val prefix = supportValue(IrcISupport.PREFIX)
-      ?: return Pair(defaultPrefixes, defaultPrefixModes)
-
-    if (prefix.startsWith("(") && prefix.contains(")")) {
-      val (prefixModes, prefixes) = prefix.substringAfter('(')
-        .split(')', limit = 2)
-        .map(String::toList)
-
-      return Pair(prefixModes, prefixes)
-    } else if (prefix.isBlank()) {
-      return Pair(defaultPrefixes, defaultPrefixModes)
-    } else if ((prefix.toSet() intersect defaultPrefixes.toSet()).isNotEmpty()) {
-      val (prefixes, prefixModes) = defaultPrefixes.zip(defaultPrefixModes)
-        .filter { prefix.contains(it.second) }
-        .unzip()
-
-      return Pair(prefixModes, prefixes)
-    } else if ((prefix.toSet() intersect defaultPrefixModes.toSet()).isNotEmpty()) {
-      val (prefixes, prefixModes) = defaultPrefixes.zip(defaultPrefixModes)
-        .filter { prefix.contains(it.first) }
-        .unzip()
-
-      return Pair(prefixModes, prefixes)
-    }
-
-    return Pair(defaultPrefixes, defaultPrefixModes)
-  }
-
   override fun setIdentity(identityId: IdentityId) {
     state.update {
       copy(identity = identity)
@@ -547,8 +494,10 @@ open class Network(
       if (isConnected) {
         copy(connected = true)
       } else {
-        ircChannels.values.forEach(session::stopSynchronize)
-        ircUsers.values.forEach(session::stopSynchronize)
+        session?.let {
+          ircChannels.values.forEach(it::stopSynchronize)
+          ircUsers.values.forEach(it::stopSynchronize)
+        }
         copy(
           connected = isConnected,
           myNick = "",
@@ -721,17 +670,4 @@ open class Network(
     }
     super.setCodecForDecoding(codecForDecoding)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    NetworkState(
-      networkId = networkId
-    )
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkConfig.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkConfig.kt
index 36b4edc..76f77c4 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkConfig.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkConfig.kt
@@ -17,12 +17,13 @@ import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.into
 import de.justjanne.libquassel.protocol.variant.qVariant
-import kotlinx.coroutines.flow.MutableStateFlow
 
 open class NetworkConfig(
-  session: Session
-) : SyncableObject(session, "NetworkConfig"), NetworkConfigStub {
-  override fun init() {
+  session: Session? = null,
+  state: NetworkConfigState = NetworkConfigState()
+) : StatefulSyncableObject<NetworkConfigState>(session, "NetworkConfig", state),
+  NetworkConfigStub {
+  init {
     renameObject("GlobalNetworkConfig")
   }
 
@@ -116,15 +117,4 @@ open class NetworkConfig(
     }
     super.setStandardCtcp(enabled)
   }
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun state() = flow().value
-
-  @Suppress("NOTHING_TO_INLINE")
-  inline fun flow() = state
-
-  @PublishedApi
-  internal val state = MutableStateFlow(
-    NetworkConfigState()
-  )
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt
new file mode 100644
index 0000000..b30b70c
--- /dev/null
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt
@@ -0,0 +1,48 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.syncables
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+abstract class StatefulSyncableObject<T>(
+  session: Session?,
+  className: String,
+  state: T
+) : SyncableObject(session, className) {
+  override fun toString(): String {
+    return "$className(objectName=${objectName}, state=${state()})"
+  }
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (other !is StatefulSyncableObject<*>) return false
+    if (!super.equals(other)) return false
+
+    if (state() != other.state()) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = super.hashCode()
+    result = 31 * result + state().hashCode()
+    return result
+  }
+
+  @Suppress("NOTHING_TO_INLINE")
+  inline fun state() = flow().value
+
+  @Suppress("NOTHING_TO_INLINE")
+  inline fun flow() = state
+
+  @PublishedApi
+  internal val state = MutableStateFlow(state)
+}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableObject.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableObject.kt
index f3e994a..fc922fa 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableObject.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableObject.kt
@@ -13,7 +13,7 @@ package de.justjanne.libquassel.protocol.syncables
 import de.justjanne.libquassel.protocol.serializers.qt.StringSerializerUtf8
 
 abstract class SyncableObject(
-  override var session: Session,
+  override var session: Session?,
   override val className: String
 ) : SyncableStub {
   final override var objectName: String = ""
@@ -29,8 +29,8 @@ abstract class SyncableObject(
       objectName = newName
     } else if (oldName != newName) {
       objectName = newName
-      session.objectRepository.rename(this, newName)
-      session.objectRenamed(
+      session?.objectRepository?.rename(this, newName)
+      session?.objectRenamed(
         StringSerializerUtf8.serializeRaw(className),
         oldName,
         newName
@@ -38,6 +38,19 @@ abstract class SyncableObject(
     }
   }
 
-  override fun init() = Unit
-  override fun deinit() = Unit
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (other !is SyncableObject) return false
+
+    if (className != other.className) return false
+    if (objectName != other.objectName) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = className.hashCode()
+    result = 31 * result + objectName.hashCode()
+    return result
+  }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableStub.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableStub.kt
index 1352dcc..b137490 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableStub.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/SyncableStub.kt
@@ -20,23 +20,20 @@ interface SyncableStub {
   val className: String
   val objectName: String
   val initialized: Boolean
-  val session: Session
+  val session: Session?
 
   fun fromVariantMap(properties: QVariantMap)
   fun toVariantMap(): QVariantMap
 
-  fun init()
-  fun deinit()
-
   fun sync(target: ProtocolSide, function: String, vararg arg: QVariant_) {
     if (initialized) {
-      session.sync(target, className, objectName, function, arg.toList())
+      session?.sync(target, className, objectName, function, arg.toList())
     }
   }
 
   fun rpc(target: ProtocolSide, function: String, vararg arg: QVariant_) {
     if (initialized) {
-      session.rpc(target, function, arg.toList())
+      session?.rpc(target, function, arg.toList())
     }
   }
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/NetworkState.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/NetworkState.kt
index c2bf063..6f5a7d8 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/NetworkState.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/NetworkState.kt
@@ -31,9 +31,6 @@ data class NetworkState(
   val currentServer: String = "",
   val connected: Boolean = false,
   val connectionState: ConnectionState = ConnectionState.Disconnected,
-  val prefixes: List<Char> = emptyList(),
-  val prefixModes: List<Char> = emptyList(),
-  val channelModes: Map<ChannelModeType, Set<Char>> = emptyMap(),
   val ircUsers: Map<String, IrcUser> = emptyMap(),
   val ircChannels: Map<String, IrcChannel> = emptyMap(),
   val supports: Map<String, String?> = emptyMap(),
@@ -62,6 +59,17 @@ data class NetworkState(
   val codecForEncoding: String = "UTF_8",
   val codecForDecoding: String = "UTF_8"
 ) {
+  val prefixes: List<Char>
+  val prefixModes: List<Char>
+  val channelModes: Map<ChannelModeType, Set<Char>>
+
+  init {
+    val (prefixes, prefixModes) = determinePrefixes()
+    this.prefixes = prefixes
+    this.prefixModes = prefixModes
+    this.channelModes = determineChannelModeTypes()
+  }
+
   fun identifier() = "${networkId.id}"
 
   fun caseMapper() = IrcCaseMapper[supportValue(IrcISupport.CASEMAPPING)]
@@ -94,4 +102,47 @@ data class NetworkState(
       it.value.contains(mode)
     }?.key
   }
+
+  private fun determinePrefixes(): Pair<List<Char>, List<Char>> {
+    val defaultPrefixes = listOf('~', '&', '@', '%', '+')
+    val defaultPrefixModes = listOf('q', 'a', 'o', 'h', 'v')
+
+    val prefix = supportValue(IrcISupport.PREFIX)
+      ?: return Pair(defaultPrefixes, defaultPrefixModes)
+
+    if (prefix.startsWith("(") && prefix.contains(")")) {
+      val (prefixModes, prefixes) = prefix.substringAfter('(')
+        .split(')', limit = 2)
+        .map(String::toList)
+
+      return Pair(prefixModes, prefixes)
+    } else if (prefix.isBlank()) {
+      return Pair(defaultPrefixes, defaultPrefixModes)
+    } else if ((prefix.toSet() intersect defaultPrefixes.toSet()).isNotEmpty()) {
+      val (prefixes, prefixModes) = defaultPrefixes.zip(defaultPrefixModes)
+        .filter { prefix.contains(it.second) }
+        .unzip()
+
+      return Pair(prefixModes, prefixes)
+    } else if ((prefix.toSet() intersect defaultPrefixModes.toSet()).isNotEmpty()) {
+      val (prefixes, prefixModes) = defaultPrefixes.zip(defaultPrefixModes)
+        .filter { prefix.contains(it.first) }
+        .unzip()
+
+      return Pair(prefixModes, prefixes)
+    }
+
+    return Pair(defaultPrefixes, defaultPrefixModes)
+  }
+
+  private fun determineChannelModeTypes(): Map<ChannelModeType, Set<Char>> {
+    return ChannelModeType.values()
+      .zip(
+        supportValue(IrcISupport.CHANMODES)
+          ?.split(',', limit = ChannelModeType.values().size)
+          ?.map(String::toSet)
+          .orEmpty()
+      )
+      .toMap()
+  }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferSyncerStub.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferSyncerStub.kt
index d61c3fa..f8a1955 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferSyncerStub.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferSyncerStub.kt
@@ -140,12 +140,12 @@ interface BufferSyncerStub : SyncableStub {
   }
 
   @SyncedCall(target = ProtocolSide.CLIENT)
-  fun setBufferActivity(buffer: BufferId, count: Int) {
+  fun setBufferActivity(buffer: BufferId, types: Int) {
     sync(
       target = ProtocolSide.CLIENT,
       "setBufferActivity",
       qVariant(buffer, QuasselType.BufferId),
-      qVariant(count, QtType.Int),
+      qVariant(types, QtType.Int),
     )
   }
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/NetworkStub.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/NetworkStub.kt
index e1e0116..5b54584 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/NetworkStub.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/NetworkStub.kt
@@ -350,6 +350,7 @@ interface NetworkStub : SyncableStub {
       qVariant(hostmask, QtType.QString),
     )
   }
+
   @SyncedCall(target = ProtocolSide.CLIENT)
   fun addIrcChannel(channel: String) {
     sync(
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/indices.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/indices.kt
similarity index 86%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/indices.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/indices.kt
index ca42d8b..1bafda7 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/indices.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/indices.kt
@@ -8,6 +8,6 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
 inline val <K, V> Map<K, V>.indices get() = 0 until size
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/plus.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/insert.kt
similarity index 78%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/plus.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/insert.kt
index ff91f83..4761e9d 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/plus.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/insert.kt
@@ -8,10 +8,9 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
-@Suppress("NOTHING_TO_INLINE")
-inline fun <T> List<T>.insert(value: T, pos: Int = size): List<T> {
+fun <T> List<T>.insert(value: T, pos: Int = size): List<T> {
   return if (pos <= 0) {
     listOf(value) + this
   } else if (pos >= size) {
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/move.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
similarity index 55%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/move.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
index 63d7016..22f1491 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/move.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
@@ -8,18 +8,15 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
-@Suppress("NOTHING_TO_INLINE")
-inline fun <T> List<T>.move(value: T, pos: Int = size): List<T> {
+fun <T> List<T>.move(value: T, pos: Int = size): List<T> {
   val newPos = pos.coerceIn(0, size)
   val oldPos = indexOf(value)
 
-  return if (oldPos > newPos) {
-    remove(value).insert(value, newPos)
-  } else if (newPos > oldPos) {
-    remove(value).insert(value, newPos - 1)
-  } else {
-    this
+  return when {
+    newPos > oldPos -> remove(value).insert(value, newPos - 1)
+    newPos < oldPos -> remove(value).insert(value, newPos)
+    else -> this
   }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/pairs.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/pairs.kt
similarity index 87%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/pairs.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/pairs.kt
index 49305be..92e0668 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/pairs.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/pairs.kt
@@ -8,7 +8,10 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
+
+import org.bouncycastle.util.io.Streams
+import java.util.stream.Stream
 
 /**
  * Returns a partitioned list of pairs
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/remove.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
similarity index 67%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/remove.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
index fde9dcf..430ab26 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/remove.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
@@ -8,7 +8,6 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
-@Suppress("NOTHING_TO_INLINE")
-inline fun <T> List<T>.remove(value: T): List<T> = this.filter { it != value }
+fun <T> List<T>.remove(value: T): List<T> = this.filter { it != value }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/transpose.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/transpose.kt
similarity index 64%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/transpose.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/transpose.kt
index c965889..787ecc0 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/transpose.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/transpose.kt
@@ -8,13 +8,15 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
+import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.QVariant_
+import de.justjanne.libquassel.protocol.variant.qVariant
 
-fun List<QVariantMap>.transpose(): Map<String, QVariantList> =
+fun List<QVariantMap>.transpose(): QVariantMap =
   flatMap { it.keys }.toSet().map { key ->
-    Pair(key, map { it[key] as QVariant_ })
+    Pair(key, qVariant(map { it[key] as QVariant_ }, QtType.QVariantList))
   }.toMap()
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/triples.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/triples.kt
similarity index 94%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/triples.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/triples.kt
index 36bff4e..16123d2 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/triples.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/triples.kt
@@ -8,7 +8,7 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.util
+package de.justjanne.libquassel.protocol.util.collections
 
 /**
  * Returns a partitioned list of triples
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 b40f600..671fecc 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
@@ -10,7 +10,7 @@
 
 package de.justjanne.libquassel.protocol.variant
 
-import de.justjanne.libquassel.protocol.util.pairs
+import de.justjanne.libquassel.protocol.util.collections.pairs
 
 /**
  * Simple alias for a generic QVariantList type
diff --git a/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/types/SignedIdProxy.java b/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/types/SignedIdProxy.java
new file mode 100644
index 0000000..03fb496
--- /dev/null
+++ b/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/types/SignedIdProxy.java
@@ -0,0 +1,36 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.types;
+
+import de.justjanne.libquassel.protocol.models.ids.SignedId;
+import de.justjanne.libquassel.protocol.models.ids.SignedIdKt;
+
+public class SignedIdProxy {
+  private SignedIdProxy() {
+
+  }
+
+  public static boolean isValidId(SignedId<Integer> data) {
+    return SignedIdKt.isValidId(data);
+  }
+
+  public static boolean isValidId64(SignedId<Long> data) {
+    return SignedIdKt.isValidId64(data);
+  }
+
+  public static <T extends Number & Comparable<T>> String toString(SignedId<T> data) {
+    return data.toString();
+  }
+
+  public static <T extends Number & Comparable<T>> int hashCode(SignedId<T> data) {
+    return data.hashCode();
+  }
+}
diff --git a/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/util/collections/PairsProxy.java b/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/util/collections/PairsProxy.java
new file mode 100644
index 0000000..f6a9084
--- /dev/null
+++ b/libquassel-protocol/src/test/java/de/justjanne/libquassel/protocol/util/collections/PairsProxy.java
@@ -0,0 +1,27 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.util.collections;
+
+import kotlin.jvm.functions.Function2;
+
+import java.util.List;
+
+public class PairsProxy {
+  private PairsProxy() {
+  }
+
+  public static <T, R> List<R> call(
+    Iterable<T> iterable,
+    Function2<T, T, R> transformer
+  ) {
+    return PairsKt.pairs(iterable, transformer);
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializerTest.kt
index ccd7435..ae5fe8e 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitAckSerializerTest.kt
@@ -23,11 +23,45 @@ import de.justjanne.libquassel.protocol.models.BackendInfo
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.models.SetupEntry
 import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
 import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("HandshakeSerializerTest")
 class ClientInitAckSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.ClientInitAck(
+      coreConfigured = null,
+      backendInfo = emptyList(),
+      authenticatorInfo = emptyList(),
+      featureSet = FeatureSet.none()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 13 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x1Au,
+      // ClientInitAck
+      0x00u, 0x43u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu,
+      0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x6Bu,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
   @Test
   fun testSimple() = handshakeSerializerTest(
     HandshakeMessage.ClientInitAck(
@@ -36,7 +70,21 @@ class ClientInitAckSerializerTest {
       authenticatorInfo = emptyList(),
       featureSet = FeatureSet.none()
     ),
-    // byteBufferOf(0x00u)
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x43u, 0x6Fu, 0x72u, 0x65u, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u, 0x72u, 0x65u, 0x73u, 0x00u, 0x00u, 0x00u, 0x03u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Fu, 0x53u, 0x74u,
+      0x6Fu, 0x72u, 0x61u, 0x67u, 0x65u, 0x42u, 0x61u, 0x63u, 0x6Bu, 0x65u, 0x6Eu, 0x64u, 0x73u, 0x00u, 0x00u, 0x00u,
+      0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Du, 0x41u,
+      0x75u, 0x74u, 0x68u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x63u, 0x61u, 0x74u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x09u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x43u, 0x6Fu,
+      0x6Eu, 0x66u, 0x69u, 0x67u, 0x75u, 0x72u, 0x65u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u, 0x72u, 0x65u, 0x4Cu, 0x69u,
+      0x73u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
   )
 
   @Test
@@ -145,6 +193,240 @@ class ClientInitAckSerializerTest {
       ),
       featureSet = FeatureSet.none()
     ),
-    // byteBufferOf(0x00u)
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x43u, 0x6Fu, 0x72u, 0x65u, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u, 0x72u, 0x65u, 0x73u, 0x00u, 0x00u, 0x00u, 0x03u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Fu, 0x53u, 0x74u,
+      0x6Fu, 0x72u, 0x61u, 0x67u, 0x65u, 0x42u, 0x61u, 0x63u, 0x6Bu, 0x65u, 0x6Eu, 0x64u, 0x73u, 0x00u, 0x00u, 0x00u,
+      0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x00u,
+      0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x4Bu, 0x00u,
+      0x65u, 0x00u, 0x79u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x1Au, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x65u,
+      0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u,
+      0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x49u, 0x00u, 0x73u, 0x00u, 0x44u, 0x00u, 0x65u,
+      0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x01u,
+      0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u, 0x6Cu, 0x00u, 0x61u,
+      0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x63u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u,
+      0x70u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u,
+      0x02u, 0x68u, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x20u,
+      0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x6Cu,
+      0x00u, 0x65u, 0x00u, 0x2Du, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x20u,
+      0x00u, 0x64u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u,
+      0x00u, 0x20u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x20u,
+      0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x6Fu, 0x00u, 0x65u,
+      0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u,
+      0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x6Eu,
+      0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x2Eu,
+      0x00u, 0x20u, 0x00u, 0x49u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x73u,
+      0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x20u,
+      0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x6Du, 0x00u, 0x61u, 0x00u, 0x6Cu,
+      0x00u, 0x6Cu, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x65u,
+      0x00u, 0x64u, 0x00u, 0x69u, 0x00u, 0x75u, 0x00u, 0x6Du, 0x00u, 0x2Du, 0x00u, 0x73u, 0x00u, 0x69u, 0x00u, 0x7Au,
+      0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u,
+      0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x61u,
+      0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u,
+      0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x72u, 0x00u, 0x65u,
+      0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x20u,
+      0x00u, 0x76u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u,
+      0x00u, 0x20u, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x20u,
+      0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x20u, 0x00u, 0x79u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x20u,
+      0x00u, 0x51u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x20u,
+      0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x68u, 0x00u, 0x6Fu,
+      0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x72u,
+      0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x61u,
+      0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x68u,
+      0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Du,
+      0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x69u,
+      0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x75u, 0x00u, 0x6Eu,
+      0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x2Cu,
+      0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x20u,
+      0x00u, 0x79u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Cu, 0x00u, 0x79u,
+      0x00u, 0x20u, 0x00u, 0x65u, 0x00u, 0x78u, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x65u, 0x00u, 0x77u, 0x00u, 0x20u, 0x00u, 0x75u, 0x00u, 0x73u,
+      0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x75u,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x79u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x20u,
+      0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x42u,
+      0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x49u, 0x00u, 0x64u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x00u, 0x00u,
+      0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x4Bu, 0x00u, 0x65u,
+      0x00u, 0x79u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u,
+      0x65u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u,
+      0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x50u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+      0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x53u, 0x00u,
+      0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u,
+      0x75u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u,
+      0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x6Eu, 0x00u, 0x61u,
+      0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u,
+      0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u,
+      0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu,
+      0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u,
+      0x68u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u,
+      0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x15u, 0x38u, 0x00u, 0x00u, 0x00u, 0x10u,
+      0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u,
+      0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u,
+      0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u, 0x00u,
+      0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Fu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u,
+      0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u,
+      0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+      0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u,
+      0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu,
+      0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u,
+      0x68u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u,
+      0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x08u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u,
+      0x15u, 0x38u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u,
+      0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u,
+      0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u,
+      0x49u, 0x00u, 0x73u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u,
+      0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u,
+      0x73u, 0x00u, 0x70u, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u,
+      0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x73u,
+      0x00u, 0x74u, 0x00u, 0x67u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x00u,
+      0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x63u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x70u,
+      0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x36u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x67u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u,
+      0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x20u, 0x00u, 0x54u, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x62u, 0x00u,
+      0x6Fu, 0x00u, 0x20u, 0x00u, 0x42u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x62u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u,
+      0x20u, 0x00u, 0x48u, 0x00u, 0x44u, 0x00u, 0x21u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x42u, 0x00u, 0x61u, 0x00u,
+      0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x67u,
+      0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x0Du, 0x41u, 0x75u, 0x74u, 0x68u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x63u, 0x61u, 0x74u, 0x6Fu, 0x72u,
+      0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x07u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u,
+      0x00u, 0x4Bu, 0x00u, 0x65u, 0x00u, 0x79u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u,
+      0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u,
+      0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u,
+      0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x49u, 0x00u, 0x73u, 0x00u,
+      0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u,
+      0x01u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u,
+      0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u,
+      0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x73u,
+      0x00u, 0x63u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x70u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x01u, 0x10u, 0x00u, 0x44u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u,
+      0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u,
+      0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u,
+      0x20u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x61u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u,
+      0x20u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x6Du, 0x00u,
+      0x6Fu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u,
+      0x69u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x2Cu, 0x00u, 0x20u, 0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+      0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x64u, 0x00u,
+      0x20u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x20u, 0x00u,
+      0x68u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u,
+      0x6Eu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u,
+      0x64u, 0x00u, 0x20u, 0x00u, 0x70u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u,
+      0x72u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u,
+      0x65u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u,
+      0x73u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u,
+      0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u,
+      0x68u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x78u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u,
+      0x73u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x70u, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x42u, 0x00u,
+      0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u,
+      0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x07u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x4Bu, 0x00u, 0x65u, 0x00u, 0x79u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u,
+      0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u,
+      0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u,
+      0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x44u, 0x00u, 0x4Eu,
+      0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x50u, 0x00u, 0x61u,
+      0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u, 0x42u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u, 0x46u, 0x00u, 0x69u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x18u,
+      0x00u, 0x55u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x41u, 0x00u, 0x74u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u,
+      0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x53u, 0x00u, 0x65u,
+      0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u,
+      0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x00u,
+      0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u,
+      0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x64u,
+      0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x3Au, 0x00u, 0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u,
+      0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x68u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x08u,
+      0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x01u,
+      0x85u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x44u, 0x00u,
+      0x4Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x42u,
+      0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x46u, 0x00u, 0x69u,
+      0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu,
+      0xFFu, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x55u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x41u, 0x00u, 0x74u, 0x00u,
+      0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x12u,
+      0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u,
+      0x00u, 0x61u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x15u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u,
+      0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u,
+      0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x64u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x3Au,
+      0x00u, 0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x68u,
+      0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u,
+      0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u,
+      0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x01u,
+      0x85u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x64u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u,
+      0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u,
+      0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u,
+      0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au,
+      0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u,
+      0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu,
+      0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x61u,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x0Eu, 0x00u, 0x42u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x46u, 0x00u, 0x69u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x46u, 0x00u, 0x69u, 0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u,
+      0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x55u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x41u, 0x00u, 0x74u, 0x00u, 0x74u,
+      0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x55u, 0x00u, 0x49u, 0x00u, 0x44u, 0x00u, 0x20u, 0x00u, 0x41u, 0x00u,
+      0x74u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x00u,
+      0x00u, 0x12u, 0x00u, 0x49u, 0x00u, 0x73u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x75u,
+      0x00u, 0x6Cu, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u,
+      0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x61u,
+      0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x4Cu, 0x00u,
+      0x44u, 0x00u, 0x41u, 0x00u, 0x50u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u,
+      0x63u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x70u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x50u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u,
+      0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u,
+      0x00u, 0x20u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x75u,
+      0x00u, 0x73u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x20u,
+      0x00u, 0x4Cu, 0x00u, 0x44u, 0x00u, 0x41u, 0x00u, 0x50u, 0x00u, 0x20u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x42u, 0x00u, 0x61u,
+      0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u,
+      0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x4Cu, 0x00u, 0x44u, 0x00u, 0x41u, 0x00u, 0x50u, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x43u, 0x6Fu, 0x6Eu, 0x66u, 0x69u, 0x67u, 0x75u, 0x72u,
+      0x65u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x0Bu, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u, 0x72u, 0x65u, 0x4Cu, 0x69u, 0x73u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Bu,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
   )
 }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitRejectSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitRejectSerializerTest.kt
new file mode 100644
index 0000000..faa0f21
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitRejectSerializerTest.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class ClientInitRejectSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.ClientInitReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 16 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x20u,
+      // ClientInitReject
+      0x00u, 0x43u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu,
+      0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testEmpty() = handshakeSerializerTest(
+    HandshakeMessage.ClientInitReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0xFFu, 0xFFu, 0xFFu, 0xFFu,
+    )
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.ClientInitReject(
+      errorString = "hm. I've lost a machine.. literally _lost_. it responds to ping, it works completely, I just " +
+        "can't figure out where in my apartment it is."
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x01u, 0x14u, 0x00u, 0x68u, 0x00u, 0x6Du, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x49u, 0x00u, 0x27u,
+      0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x65u, 0x00u, 0x2Eu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u,
+      0x00u, 0x72u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x5Fu, 0x00u, 0x6Cu,
+      0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x5Fu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x64u,
+      0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x70u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x67u, 0x00u, 0x2Cu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x77u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x70u,
+      0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x2Cu, 0x00u, 0x20u,
+      0x00u, 0x49u, 0x00u, 0x20u, 0x00u, 0x6Au, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x63u,
+      0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x27u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x67u,
+      0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x77u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x61u, 0x00u, 0x72u,
+      0x00u, 0x74u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x2Eu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitSerializerTest.kt
index 13c974c..a6cc1e3 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientInitSerializerTest.kt
@@ -22,9 +22,40 @@ import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("HandshakeSerializerTest")
 class ClientInitSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.ClientInit(
+      clientVersion = null,
+      buildDate = null,
+      featureSet = FeatureSet.none()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 10 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x14u,
+      0x00u, 0x43u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu,
+      0x00u, 0x69u, 0x00u, 0x74u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
   @Test
   fun testSimple() = handshakeSerializerTest(
     HandshakeMessage.ClientInit(
@@ -70,6 +101,84 @@ class ClientInitSerializerTest {
       buildDate = "2020-04-27T22:21:17Z",
       featureSet = FeatureSet.all()
     ),
-    // byteBufferOf(0x00u)
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Du, 0x43u, 0x6Cu, 0x69u, 0x65u, 0x6Eu, 0x74u,
+      0x56u, 0x65u, 0x72u, 0x73u, 0x69u, 0x6Fu, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x01u, 0x04u,
+      0x00u, 0x51u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x64u,
+      0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u, 0x3Cu, 0x00u, 0x61u, 0x00u, 0x20u,
+      0x00u, 0x68u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x3Du, 0x00u, 0x22u, 0x00u, 0x68u, 0x00u, 0x74u,
+      0x00u, 0x74u, 0x00u, 0x70u, 0x00u, 0x73u, 0x00u, 0x3Au, 0x00u, 0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x67u, 0x00u, 0x69u,
+      0x00u, 0x74u, 0x00u, 0x2Eu, 0x00u, 0x6Bu, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x6Bu,
+      0x00u, 0x75u, 0x00u, 0x2Eu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x2Fu, 0x00u, 0x6Au, 0x00u, 0x75u, 0x00u, 0x73u,
+      0x00u, 0x74u, 0x00u, 0x4Au, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x2Fu, 0x00u, 0x51u,
+      0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x44u, 0x00u, 0x72u,
+      0x00u, 0x6Fu, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x2Du, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x2Fu, 0x00u, 0x63u,
+      0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x2Fu, 0x00u, 0x62u, 0x00u, 0x36u,
+      0x00u, 0x32u, 0x00u, 0x32u, 0x00u, 0x61u, 0x00u, 0x64u, 0x00u, 0x36u, 0x00u, 0x33u, 0x00u, 0x30u, 0x00u, 0x35u,
+      0x00u, 0x36u, 0x00u, 0x62u, 0x00u, 0x36u, 0x00u, 0x30u, 0x00u, 0x35u, 0x00u, 0x34u, 0x00u, 0x62u, 0x00u, 0x30u,
+      0x00u, 0x36u, 0x00u, 0x65u, 0x00u, 0x30u, 0x00u, 0x39u, 0x00u, 0x66u, 0x00u, 0x38u, 0x00u, 0x65u, 0x00u, 0x31u,
+      0x00u, 0x66u, 0x00u, 0x31u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x32u, 0x00u, 0x62u, 0x00u, 0x30u, 0x00u, 0x63u,
+      0x00u, 0x33u, 0x00u, 0x61u, 0x00u, 0x61u, 0x00u, 0x66u, 0x00u, 0x39u, 0x00u, 0x61u, 0x00u, 0x22u, 0x00u, 0x3Eu,
+      0x00u, 0x76u, 0x00u, 0x31u, 0x00u, 0x2Eu, 0x00u, 0x33u, 0x00u, 0x2Eu, 0x00u, 0x33u, 0x00u, 0x3Cu, 0x00u, 0x2Fu,
+      0x00u, 0x61u, 0x00u, 0x3Eu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x43u, 0x6Cu, 0x69u,
+      0x65u, 0x6Eu, 0x74u, 0x44u, 0x61u, 0x74u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u,
+      0x00u, 0x32u, 0x00u, 0x30u, 0x00u, 0x32u, 0x00u, 0x30u, 0x00u, 0x2Du, 0x00u, 0x30u, 0x00u, 0x34u, 0x00u, 0x2Du,
+      0x00u, 0x32u, 0x00u, 0x37u, 0x00u, 0x54u, 0x00u, 0x32u, 0x00u, 0x32u, 0x00u, 0x3Au, 0x00u, 0x32u, 0x00u, 0x31u,
+      0x00u, 0x3Au, 0x00u, 0x31u, 0x00u, 0x37u, 0x00u, 0x5Au, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x08u, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u, 0x72u, 0x65u, 0x73u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u,
+      0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x46u, 0x65u, 0x61u, 0x74u, 0x75u,
+      0x72u, 0x65u, 0x4Cu, 0x69u, 0x73u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u,
+      0x00u, 0x00u, 0x2Cu, 0x00u, 0x53u, 0x00u, 0x79u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x72u, 0x00u,
+      0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x4Du, 0x00u, 0x61u, 0x00u,
+      0x72u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x24u, 0x00u, 0x53u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u,
+      0x74u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u,
+      0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x53u, 0x00u, 0x61u, 0x00u,
+      0x73u, 0x00u, 0x6Cu, 0x00u, 0x45u, 0x00u, 0x78u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x6Eu, 0x00u,
+      0x61u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x48u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u,
+      0x49u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u,
+      0x4Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x73u, 0x00u,
+      0x00u, 0x00u, 0x1Cu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u,
+      0x72u, 0x00u, 0x64u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x1Cu, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x4Eu, 0x00u, 0x65u, 0x00u, 0x67u, 0x00u,
+      0x6Fu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+      0x00u, 0x00u, 0x1Eu, 0x00u, 0x56u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u,
+      0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x53u, 0x00u, 0x53u, 0x00u,
+      0x4Cu, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x43u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u,
+      0x6Du, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x44u, 0x00u, 0x63u, 0x00u, 0x63u, 0x00u,
+      0x46u, 0x00u, 0x69u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x54u, 0x00u, 0x72u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u,
+      0x73u, 0x00u, 0x66u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u,
+      0x61u, 0x00u, 0x79u, 0x00u, 0x46u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Du, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+      0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u,
+      0x70u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u,
+      0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+      0x73u, 0x00u, 0x00u, 0x00u, 0x24u, 0x00u, 0x42u, 0x00u, 0x75u, 0x00u, 0x66u, 0x00u, 0x66u, 0x00u, 0x65u, 0x00u,
+      0x72u, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x76u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u,
+      0x79u, 0x00u, 0x53u, 0x00u, 0x79u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x00u, 0x00u, 0x24u, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x48u, 0x00u,
+      0x69u, 0x00u, 0x67u, 0x00u, 0x68u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x67u, 0x00u, 0x68u, 0x00u, 0x74u, 0x00u,
+      0x73u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u,
+      0x72u, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x78u, 0x00u, 0x65u, 0x00u,
+      0x73u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Du, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u,
+      0x65u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u,
+      0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x45u, 0x00u, 0x78u, 0x00u, 0x74u, 0x00u,
+      0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x46u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u,
+      0x74u, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x4Cu, 0x00u,
+      0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x18u, 0x00u, 0x52u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u,
+      0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u, 0x42u, 0x00u,
+      0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x67u, 0x00u, 0x46u, 0x00u, 0x69u, 0x00u,
+      0x6Cu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x54u, 0x00u, 0x79u, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u,
+      0x00u, 0x00u, 0x1Eu, 0x00u, 0x45u, 0x00u, 0x63u, 0x00u, 0x64u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x43u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x66u, 0x00u, 0x70u, 0x00u, 0x4Bu, 0x00u, 0x65u, 0x00u, 0x79u, 0x00u,
+      0x73u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x4Cu, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x4Du, 0x00u,
+      0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u,
+      0x00u, 0x00u, 0x1Cu, 0x00u, 0x53u, 0x00u, 0x79u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u,
+      0x43u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x66u, 0x00u, 0x6Fu
+    )
   )
 }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginAckSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginAckSerializerTest.kt
new file mode 100644
index 0000000..98c61ac
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginAckSerializerTest.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class ClientLoginAckSerializerTest {
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.ClientLoginAck,
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu, 0x00u, 0x67u, 0x00u,
+      0x69u, 0x00u, 0x6Eu, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x6Bu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginRejectSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginRejectSerializerTest.kt
new file mode 100644
index 0000000..823d8cc
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginRejectSerializerTest.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class ClientLoginRejectSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.ClientLoginReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 17 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x22u,
+      // ClientLoginReject
+      0x00u, 0x43u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu,
+      0x00u, 0x67u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u,
+      0x00u, 0x74u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testEmpty() = handshakeSerializerTest(
+    HandshakeMessage.ClientLoginReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu, 0x00u, 0x67u, 0x00u,
+      0x69u, 0x00u, 0x6Eu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu,
+    )
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.ClientInitReject(
+      errorString = "hm. I've lost a machine.. literally _lost_. it responds to ping, it works completely, I just " +
+        "can't figure out where in my apartment it is."
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+      0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x01u, 0x14u, 0x00u, 0x68u, 0x00u, 0x6Du, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x49u, 0x00u, 0x27u,
+      0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x61u, 0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x65u, 0x00u, 0x2Eu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u,
+      0x00u, 0x72u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x5Fu, 0x00u, 0x6Cu,
+      0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x5Fu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x64u,
+      0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x70u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x67u, 0x00u, 0x2Cu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x77u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x70u,
+      0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x2Cu, 0x00u, 0x20u,
+      0x00u, 0x49u, 0x00u, 0x20u, 0x00u, 0x6Au, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x63u,
+      0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x27u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x67u,
+      0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x77u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x61u, 0x00u, 0x72u,
+      0x00u, 0x74u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x2Eu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginSerializerTest.kt
new file mode 100644
index 0000000..a110542
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/ClientLoginSerializerTest.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class ClientLoginSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.ClientLogin(
+      user = null,
+      password = null
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 11 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x16u,
+      0x00u, 0x43u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu,
+      0x00u, 0x67u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.ClientLogin(
+      user = "",
+      password = ""
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu, 0x00u, 0x67u, 0x00u,
+      0x69u, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x55u, 0x73u, 0x65u, 0x72u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x08u, 0x50u, 0x61u, 0x73u, 0x73u, 0x77u, 0x6Fu, 0x72u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() = handshakeSerializerTest(
+    HandshakeMessage.ClientLogin(
+      user = "AzureDiamond",
+      password = "hunter2"
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x43u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x4Cu, 0x00u, 0x6Fu, 0x00u, 0x67u, 0x00u,
+      0x69u, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x55u, 0x73u, 0x65u, 0x72u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x41u, 0x00u, 0x7Au, 0x00u, 0x75u, 0x00u,
+      0x72u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+      0x64u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x50u, 0x61u, 0x73u, 0x73u, 0x77u, 0x6Fu,
+      0x72u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x68u, 0x00u, 0x75u, 0x00u,
+      0x6Eu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x32u,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupAckSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupAckSerializerTest.kt
new file mode 100644
index 0000000..6d514c4
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupAckSerializerTest.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class CoreSetupAckSerializerTest {
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupAck,
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x41u, 0x00u, 0x63u, 0x00u, 0x6Bu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializerTest.kt
new file mode 100644
index 0000000..0058cea
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupDataSerializerTest.kt
@@ -0,0 +1,205 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.serializers.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class CoreSetupDataSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupData(
+      adminUser = null,
+      adminPassword = null,
+      backend = null,
+      setupData = emptyMap(),
+      authenticator = null,
+      authSetupData = emptyMap()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 13 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x1Au,
+      // CoreSetupData
+      0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u,
+      0x00u, 0x70u, 0x00u, 0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testEmpty() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupData(
+      adminUser = null,
+      adminPassword = null,
+      backend = null,
+      setupData = emptyMap(),
+      authenticator = null,
+      authSetupData = emptyMap()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u,
+      0x53u, 0x65u, 0x74u, 0x75u, 0x70u, 0x44u, 0x61u, 0x74u, 0x61u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x41u, 0x00u, 0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu,
+      0xFFu, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x41u, 0x00u, 0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u,
+      0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x42u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu,
+      0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u,
+      0x00u, 0x00u, 0x28u, 0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u,
+      0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x70u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u,
+      0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u,
+      0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x70u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupData(
+      adminUser = "AzureDiamond",
+      adminPassword = "hunter2",
+      backend = "SQLite",
+      setupData = emptyMap(),
+      authenticator = "Database",
+      authSetupData = emptyMap()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u,
+      0x53u, 0x65u, 0x74u, 0x75u, 0x70u, 0x44u, 0x61u, 0x74u, 0x61u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x41u, 0x00u, 0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x18u, 0x00u, 0x41u, 0x00u, 0x7Au, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u,
+      0x61u, 0x00u, 0x6Du, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x41u, 0x00u,
+      0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u,
+      0x77u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x68u, 0x00u, 0x75u,
+      0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x32u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x42u,
+      0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u,
+      0x65u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+      0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u,
+      0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+      0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u,
+      0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u, 0x00u,
+      0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x1Cu, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u,
+      0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+      0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupData(
+      adminUser = "AzureDiamond",
+      adminPassword = "hunter2",
+      backend = "PostgreSQL",
+      setupData = mapOf(
+        "Username" to qVariant("quassel", QtType.QString),
+        "Password" to qVariant<String?>(null, QtType.QString),
+        "Hostname" to qVariant("localhost", QtType.QString),
+        "Port" to qVariant(5432, QtType.Int),
+        "Database" to qVariant("quassel", QtType.QString),
+      ),
+      authenticator = "LDAP",
+      authSetupData = mapOf(
+        "Hostname" to qVariant("ldap://localhost", QtType.QString),
+        "Port" to qVariant(389, QtType.Int),
+        "BindDN" to qVariant<String?>(null, QtType.QString),
+        "BindPassword" to qVariant<String?>(null, QtType.QString),
+        "BaseDN" to qVariant<String?>(null, QtType.QString),
+        "Filter" to qVariant<String?>(null, QtType.QString),
+        "UidAttribute" to qVariant("uid", QtType.QString),
+      )
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x44u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u,
+      0x53u, 0x65u, 0x74u, 0x75u, 0x70u, 0x44u, 0x61u, 0x74u, 0x61u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x41u, 0x00u, 0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x18u, 0x00u, 0x41u, 0x00u, 0x7Au, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u,
+      0x61u, 0x00u, 0x6Du, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x41u, 0x00u,
+      0x64u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u,
+      0x77u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x68u, 0x00u, 0x75u,
+      0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x32u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x42u,
+      0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x67u, 0x00u,
+      0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x51u, 0x00u, 0x4Cu, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u,
+      0x6Eu, 0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u,
+      0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u,
+      0x00u, 0x10u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du,
+      0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u,
+      0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x50u, 0x00u,
+      0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u,
+      0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x12u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x68u, 0x00u,
+      0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x50u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+      0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x15u, 0x38u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x44u,
+      0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x00u,
+      0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u,
+      0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+      0x68u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x4Cu, 0x00u, 0x44u,
+      0x00u, 0x41u, 0x00u, 0x50u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x68u,
+      0x00u, 0x50u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x69u,
+      0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u,
+      0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x64u, 0x00u, 0x61u,
+      0x00u, 0x70u, 0x00u, 0x3Au, 0x00u, 0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x63u, 0x00u, 0x61u,
+      0x00u, 0x6Cu, 0x00u, 0x68u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x50u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x01u, 0x85u, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x42u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x42u, 0x00u, 0x69u,
+      0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x42u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x4Eu, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x46u, 0x00u, 0x69u, 0x00u, 0x6Cu,
+      0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u,
+      0x00u, 0x00u, 0x18u, 0x00u, 0x55u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x41u, 0x00u, 0x74u, 0x00u, 0x74u, 0x00u,
+      0x72u, 0x00u, 0x69u, 0x00u, 0x62u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x64u,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupRejectSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupRejectSerializerTest.kt
new file mode 100644
index 0000000..5ad89bf
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/CoreSetupRejectSerializerTest.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.handshake
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class CoreSetupRejectSerializerTest {
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 15 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x1Eu,
+      // CoreSetupReject
+      0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u,
+      0x00u, 0x70u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testEmpty() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupReject(
+      errorString = null
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0xFFu, 0xFFu,
+      0xFFu, 0xFFu,
+    )
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.CoreSetupReject(
+      errorString = "hm. I've lost a machine.. literally _lost_. it responds to ping, it works completely, I just " +
+        "can't figure out where in my apartment it is."
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x43u, 0x00u,
+      0x6Fu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u,
+      0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x05u, 0x45u, 0x72u, 0x72u, 0x6Fu, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u,
+      0x01u, 0x14u, 0x00u, 0x68u, 0x00u, 0x6Du, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x49u, 0x00u, 0x27u, 0x00u, 0x76u,
+      0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x61u,
+      0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x65u,
+      0x00u, 0x2Eu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x5Fu, 0x00u, 0x6Cu, 0x00u, 0x6Fu,
+      0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x5Fu, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x70u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x73u,
+      0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x70u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u,
+      0x00u, 0x2Cu, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u,
+      0x00u, 0x6Bu, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x70u, 0x00u, 0x6Cu,
+      0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x2Cu, 0x00u, 0x20u, 0x00u, 0x49u,
+      0x00u, 0x20u, 0x00u, 0x6Au, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x61u,
+      0x00u, 0x6Eu, 0x00u, 0x27u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x67u, 0x00u, 0x75u,
+      0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x77u,
+      0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x20u,
+      0x00u, 0x6Du, 0x00u, 0x79u, 0x00u, 0x20u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x61u, 0x00u, 0x72u, 0x00u, 0x74u,
+      0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x20u,
+      0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x2Eu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
new file mode 100644
index 0000000..a4c7a22
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/handshake/SessionInitSerializerTest.kt
@@ -0,0 +1,209 @@
+/*
+ * 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.handshake
+
+import de.justjanne.bitflags.of
+import de.justjanne.libquassel.protocol.models.BufferInfo
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.models.flags.BufferType
+import de.justjanne.libquassel.protocol.models.ids.BufferId
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.syncables.Identity
+import de.justjanne.libquassel.protocol.syncables.state.IdentityState
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.handshakeSerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("HandshakeSerializerTest")
+class SessionInitSerializerTest {
+
+  @Test
+  fun testEmptyMap() = handshakeSerializerTest(
+    HandshakeMessage.SessionInit(
+      identities = emptyList(),
+      bufferInfos = emptyList(),
+      networkIds = emptyList()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // ByteBuffer
+      0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u,
+      // 7 bytes
+      0x00u, 0x00u, 0x00u, 0x07u,
+      // MsgType
+      0x4Du, 0x73u, 0x67u, 0x54u, 0x79u, 0x70u, 0x65u,
+      // String
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u,
+      // 11 2-byte chars
+      0x00u, 0x00u, 0x00u, 0x16u,
+      0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x49u,
+      0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x74u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = handshakeSerializerTest(
+    HandshakeMessage.SessionInit(
+      identities = emptyList(),
+      bufferInfos = emptyList(),
+      networkIds = emptyList()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x53u, 0x00u,
+      0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x53u, 0x65u, 0x73u, 0x73u,
+      0x69u, 0x6Fu, 0x6Eu, 0x53u, 0x74u, 0x61u, 0x74u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x03u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x42u, 0x00u, 0x75u, 0x00u, 0x66u, 0x00u, 0x66u, 0x00u, 0x65u, 0x00u,
+      0x72u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x4Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x09u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u,
+      0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+      0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() = handshakeSerializerTest(
+    HandshakeMessage.SessionInit(
+      identities = listOf(
+        Identity(
+          state = IdentityState(
+            identityId = IdentityId(1)
+          )
+        ).toVariantMap()
+      ),
+      bufferInfos = listOf(
+        BufferInfo(
+          networkId = NetworkId(4),
+          bufferId = BufferId(1337),
+          bufferName = "#quassel",
+          type = BufferType.of(BufferType.Channel),
+        )
+      ),
+      networkIds = listOf(
+        NetworkId(4)
+      )
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Du, 0x73u, 0x67u,
+      0x54u, 0x79u, 0x70u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x53u, 0x00u,
+      0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x53u, 0x65u, 0x73u, 0x73u,
+      0x69u, 0x6Fu, 0x6Eu, 0x53u, 0x74u, 0x61u, 0x74u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x03u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x42u, 0x00u, 0x75u, 0x00u, 0x66u, 0x00u, 0x66u, 0x00u, 0x65u, 0x00u,
+      0x72u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x42u, 0x75u, 0x66u,
+      0x66u, 0x65u, 0x72u, 0x49u, 0x6Eu, 0x66u, 0x6Fu, 0x00u, 0x00u, 0x00u, 0x05u, 0x39u, 0x00u, 0x00u, 0x00u, 0x04u,
+      0x00u, 0x02u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x08u, 0x23u, 0x71u, 0x75u, 0x61u, 0x73u, 0x73u,
+      0x65u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x4Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x4Eu, 0x65u, 0x74u, 0x77u,
+      0x6Fu, 0x72u, 0x6Bu, 0x49u, 0x64u, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x49u,
+      0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x65u,
+      0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x09u, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x13u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x79u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x0Bu, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x49u, 0x64u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x01u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u,
+      0x69u, 0x00u, 0x74u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x3Cu, 0x00u, 0x65u, 0x00u, 0x6Du, 0x00u, 0x70u, 0x00u, 0x74u,
+      0x00u, 0x79u, 0x00u, 0x3Eu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x6Cu,
+      0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x73u, 0x00u,
+      0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u,
+      0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x61u,
+      0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x00u,
+      0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x61u, 0x00u, 0x77u, 0x00u,
+      0x61u, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u,
+      0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x14u, 0x00u, 0x61u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u,
+      0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au,
+      0x00u, 0x47u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x66u, 0x00u, 0x69u, 0x00u, 0x73u,
+      0x00u, 0x68u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u, 0x61u,
+      0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu,
+      0x00u, 0x6Eu, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u,
+      0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u,
+      0x00u, 0x6Fu, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x61u,
+      0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x18u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u,
+      0x00u, 0x79u, 0x00u, 0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u,
+      0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u,
+      0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x3Cu, 0x00u, 0x4Eu, 0x00u, 0x6Fu,
+      0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x2Eu, 0x00u, 0x20u,
+      0x00u, 0x4Eu, 0x00u, 0x6Fu, 0x00u, 0x20u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x6Cu,
+      0x00u, 0x79u, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x68u,
+      0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x21u, 0x00u, 0x00u, 0x00u, 0x2Au, 0x00u, 0x61u, 0x00u, 0x75u,
+      0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x52u, 0x00u, 0x65u,
+      0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u,
+      0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x22u,
+      0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x41u, 0x00u, 0x77u,
+      0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u,
+      0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x64u, 0x00u, 0x65u,
+      0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u,
+      0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x74u, 0x00u, 0x41u, 0x00u, 0x6Cu, 0x00u, 0x6Cu, 0x00u, 0x20u, 0x00u, 0x51u, 0x00u,
+      0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u,
+      0x6Cu, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x76u, 0x00u,
+      0x61u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x20u, 0x00u,
+      0x66u, 0x00u, 0x72u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x20u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u,
+      0x20u, 0x00u, 0x66u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x6Fu, 0x00u, 0x66u, 0x00u,
+      0x20u, 0x00u, 0x74u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x20u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x72u, 0x00u,
+      0x74u, 0x00u, 0x68u, 0x00u, 0x2Eu, 0x00u, 0x2Eu, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x2Eu, 0x00u, 0x64u, 0x00u,
+      0x65u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u,
+      0x79u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x45u, 0x00u,
+      0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x6Bu, 0x00u, 0x69u, 0x00u, 0x63u,
+      0x00u, 0x6Bu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u,
+      0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x34u, 0x00u, 0x4Bu, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x67u, 0x00u, 0x61u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u,
+      0x20u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x20u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u,
+      0x77u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x21u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u,
+      0x70u, 0x00u, 0x61u, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u,
+      0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x68u, 0x00u, 0x68u, 0x00u, 0x74u,
+      0x00u, 0x74u, 0x00u, 0x70u, 0x00u, 0x3Au, 0x00u, 0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u,
+      0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x2Du, 0x00u, 0x69u, 0x00u, 0x72u, 0x00u, 0x63u,
+      0x00u, 0x2Eu, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x67u, 0x00u, 0x20u, 0x00u, 0x2Du, 0x00u, 0x20u, 0x00u, 0x43u,
+      0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x66u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x2Eu,
+      0x00u, 0x20u, 0x00u, 0x41u, 0x00u, 0x6Eu, 0x00u, 0x79u, 0x00u, 0x77u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x65u, 0x00u, 0x2Eu, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x68u, 0x00u, 0x68u, 0x00u, 0x74u, 0x00u, 0x74u, 0x00u, 0x70u, 0x00u, 0x3Au, 0x00u,
+      0x2Fu, 0x00u, 0x2Fu, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u,
+      0x6Cu, 0x00u, 0x2Du, 0x00u, 0x69u, 0x00u, 0x72u, 0x00u, 0x63u, 0x00u, 0x2Eu, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+      0x67u, 0x00u, 0x20u, 0x00u, 0x2Du, 0x00u, 0x20u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+      0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u,
+      0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x79u, 0x00u, 0x2Eu, 0x00u, 0x20u, 0x00u, 0x41u, 0x00u, 0x6Eu, 0x00u,
+      0x79u, 0x00u, 0x77u, 0x00u, 0x68u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x2Eu,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/BoolSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/BoolSerializerTest.kt
index 21a9955..263495a 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/BoolSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/BoolSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class BoolSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializerTest.kt
index 20917e5..f013a3f 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteBufferSerializerTest.kt
@@ -23,9 +23,11 @@ import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.matchers.ByteBufferMatcher
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import java.nio.ByteBuffer
 
+@Tag("QtSerializerTest")
 class ByteBufferSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteSerializerTest.kt
index 28548e9..4c2e45e 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ByteSerializerTest.kt
@@ -22,9 +22,11 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import kotlin.experimental.inv
 
+@Tag("QtSerializerTest")
 class ByteSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/DoubleSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/DoubleSerializerTest.kt
index f3dc9af..d6ddd7f 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/DoubleSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/DoubleSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class DoubleSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/FloatSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/FloatSerializerTest.kt
index 7b6b445..da67e26 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/FloatSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/FloatSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class FloatSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/HandshakeMapSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/HandshakeMapSerializerTest.kt
index 108d4f5..6fa8545 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/HandshakeMapSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/HandshakeMapSerializerTest.kt
@@ -24,8 +24,10 @@ import de.justjanne.libquassel.protocol.testutil.matchers.MapMatcher
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import de.justjanne.libquassel.protocol.variant.qVariant
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class HandshakeMapSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/IntSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/IntSerializerTest.kt
index 9131635..33e7ff2 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/IntSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/IntSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class IntSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/LongSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/LongSerializerTest.kt
index ea5455a..e237b81 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/LongSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/LongSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class LongSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QCharSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QCharSerializerTest.kt
index 4fa348e..e1be2e5 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QCharSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QCharSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.matchers.BomMatcherChar
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class QCharSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateSerializerTest.kt
index 02a3b23..6331aab 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateSerializerTest.kt
@@ -23,10 +23,12 @@ import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.matchers.TemporalMatcher
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import org.threeten.bp.LocalDate
 import org.threeten.bp.Month
 
+@Tag("QtSerializerTest")
 class QDateSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateTimeSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateTimeSerializerTest.kt
index 872359b..7e5b6c9 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateTimeSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QDateTimeSerializerTest.kt
@@ -23,6 +23,7 @@ import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.matchers.TemporalMatcher
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertThrows
 import org.threeten.bp.Instant
@@ -33,6 +34,7 @@ import org.threeten.bp.ZoneOffset
 import org.threeten.bp.chrono.JapaneseDate
 import org.threeten.bp.temporal.Temporal
 
+@Tag("QtSerializerTest")
 class QDateTimeSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QTimeSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QTimeSerializerTest.kt
index 22a12aa..b324361 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QTimeSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QTimeSerializerTest.kt
@@ -23,9 +23,11 @@ import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.matchers.TemporalMatcher
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import org.threeten.bp.LocalTime
 
+@Tag("QtSerializerTest")
 class QTimeSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantListSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantListSerializerTest.kt
index 68cf646..f8234b8 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantListSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantListSerializerTest.kt
@@ -24,8 +24,10 @@ import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.qVariant
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class QVariantListSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantMapSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantMapSerializerTest.kt
index 5f3b816..f868d07 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantMapSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantMapSerializerTest.kt
@@ -25,8 +25,10 @@ import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import de.justjanne.libquassel.protocol.variant.qVariant
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class QVariantMapSerializerTest {
   @Test
   fun testIsRegistered() {
@@ -51,106 +53,12 @@ class QVariantMapSerializerTest {
       "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
+      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
   )
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializerTest.kt
index 832f9cc..123d8c7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/QVariantSerializerTest.kt
@@ -24,9 +24,11 @@ import de.justjanne.libquassel.protocol.serializers.NoSerializerForTypeException
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.variant.QVariant_
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertThrows
 
+@Tag("QtSerializerTest")
 class QVariantSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ShortSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ShortSerializerTest.kt
index ddd0833..83e8a60 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ShortSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ShortSerializerTest.kt
@@ -22,9 +22,11 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import kotlin.experimental.inv
 
+@Tag("QtSerializerTest")
 class ShortSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializerTest.kt
index 35b65a2..c9fb939 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/StringSerializerTest.kt
@@ -28,8 +28,10 @@ import de.justjanne.libquassel.protocol.testutil.testPrimitiveSerializerVariant
 import de.justjanne.libquassel.protocol.util.withRewind
 import org.hamcrest.MatcherAssert.assertThat
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class StringSerializerTest {
   @Test
   fun testIsRegistered() {
@@ -39,6 +41,13 @@ class StringSerializerTest {
     )
   }
 
+  @Test
+  fun testEmpty() {
+    assertEquals("", StringSerializerAscii.deserializeRaw(null))
+    assertEquals("", StringSerializerUtf8.deserializeRaw(null))
+    assertEquals("", StringSerializerUtf16.deserializeRaw(null))
+  }
+
   @Test
   fun testBigListOfNaughtyStrings() {
     this::class.java.getResourceAsStream("/blns.txt")!!.bufferedReader(Charsets.UTF_8).forEachLine {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UByteSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UByteSerializerTest.kt
index 7f388a6..12f13f2 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UByteSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UByteSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class UByteSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UIntSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UIntSerializerTest.kt
index 843ca87..7203cb3 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UIntSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UIntSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class UIntSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ULongSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ULongSerializerTest.kt
index 071663b..6a2ea07 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ULongSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/ULongSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class ULongSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UShortSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UShortSerializerTest.kt
index daf61be..5804e37 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UShortSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UShortSerializerTest.kt
@@ -13,8 +13,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class UShortSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UuidSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UuidSerializerTest.kt
new file mode 100644
index 0000000..61da420
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/UuidSerializerTest.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.qt
+
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+import java.util.UUID
+
+@Tag("QtSerializerTest")
+class UuidSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      UuidSerializer,
+      QtType.Uuid.serializer<UUID>(),
+    )
+  }
+
+  @Test
+  fun testSimple() = primitiveSerializerTest(
+    UuidSerializer,
+    UUID.fromString("e4335bb0-ceef-4b9f-8ceb-be19b4da34fd"),
+    byteBufferOf(
+      0xE4u, 0x33u, 0x5Bu, 0xB0u, 0xCEu, 0xEFu, 0x4Bu, 0x9Fu, 0x8Cu, 0xEBu, 0xBEu, 0x19u, 0xB4u, 0xDAu, 0x34u, 0xFDu, 
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/VoidSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/VoidSerializerTest.kt
index cccac85..37848c8 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/VoidSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/qt/VoidSerializerTest.kt
@@ -22,8 +22,10 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QtSerializerTest")
 class VoidSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferIdSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferIdSerializerTest.kt
index 5a8ef9b..0f5bb9c 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferIdSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferIdSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class BufferIdSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializerTest.kt
index 7860f42..474846a 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/BufferInfoSerializerTest.kt
@@ -28,8 +28,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class BufferInfoSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccIpDetectionModeSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccIpDetectionModeSerializerTest.kt
index 4742872..674caa7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccIpDetectionModeSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccIpDetectionModeSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class DccIpDetectionModeSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccPortSelectionModeSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccPortSelectionModeSerializerTest.kt
index 0d8dbc5..f478930 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccPortSelectionModeSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/DccPortSelectionModeSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class DccPortSelectionModeSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentityIdSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentityIdSerializerTest.kt
index 2b2d56e..a18554a 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentityIdSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IdentityIdSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class IdentityIdSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
new file mode 100644
index 0000000..ee8cabc
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcChannelSerializerTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.quassel
+
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.types.QuasselType
+import de.justjanne.libquassel.protocol.syncables.IrcChannel
+import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.matchers.MapMatcher
+import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("QuasselSerializerTest")
+class IrcChannelSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      IrcChannelSerializer,
+      QuasselType.IrcChannel.serializer<QVariantMap>(),
+    )
+  }
+
+  @Test
+  fun testEmptyMap() = primitiveSerializerTest(
+    IrcChannelSerializer,
+    emptyMap(),
+    byteBufferOf(
+      // no elements
+      0x00u, 0x00u, 0x00u, 0x00u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testNormal() = primitiveSerializerTest(
+    IrcChannelSerializer,
+    IrcChannel(
+      state = IrcChannelState(
+        network = NetworkId(4),
+        name = "#quassel"
+      )
+    ).toVariantMap(),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x23u, 0x00u, 0x71u, 0x00u, 0x75u, 0x00u,
+      0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x74u, 0x00u,
+      0x6Fu, 0x00u, 0x70u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x70u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x12u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x72u, 0x00u, 0x79u, 0x00u, 0x70u, 0x00u, 0x74u, 0x00u,
+      0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x43u, 0x00u,
+      0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x4Du, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u,
+      0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x41u, 0x00u, 0x00u,
+      0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x42u, 0x00u, 0x00u, 0x00u,
+      0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x43u, 0x00u, 0x00u, 0x00u, 0x08u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x44u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x4Du, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u,
+    ),
+    matcher = ::MapMatcher
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.kt
new file mode 100644
index 0000000..c8e246c
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/IrcUserSerializerTest.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.justjanne.libquassel.protocol.serializers.quassel
+
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.types.QuasselType
+import de.justjanne.libquassel.protocol.syncables.IrcUser
+import de.justjanne.libquassel.protocol.syncables.state.IrcUserState
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.matchers.MapMatcher
+import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("QuasselSerializerTest")
+class IrcUserSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      IrcUserSerializer,
+      QuasselType.IrcUser.serializer<QVariantMap>(),
+    )
+  }
+
+  @Test
+  fun testEmptyMap() = primitiveSerializerTest(
+    IrcUserSerializer,
+    emptyMap(),
+    byteBufferOf(
+      // no elements
+      0x00u, 0x00u, 0x00u, 0x00u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testNormal() = primitiveSerializerTest(
+    IrcUserSerializer,
+    IrcUser(
+      state = IrcUserState(
+        network = NetworkId(4),
+        nick = "AzureDiamond",
+        user = "~azure",
+        host = "127.0.0.1"
+      )
+    ).toVariantMap(),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x6Bu,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x41u, 0x00u, 0x7Au, 0x00u, 0x75u, 0x00u,
+      0x72u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+      0x64u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x7Eu, 0x00u, 0x61u, 0x00u, 0x7Au, 0x00u, 0x75u, 0x00u, 0x72u,
+      0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x68u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u,
+      0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x31u, 0x00u, 0x32u, 0x00u, 0x37u, 0x00u, 0x2Eu, 0x00u,
+      0x30u, 0x00u, 0x2Eu, 0x00u, 0x30u, 0x00u, 0x2Eu, 0x00u, 0x31u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x72u, 0x00u,
+      0x65u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x61u, 0x00u, 0x63u, 0x00u, 0x63u,
+      0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x61u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u,
+      0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x61u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u,
+      0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x6Cu,
+      0x00u, 0x65u, 0x00u, 0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x00u,
+      0x25u, 0x3Du, 0x8Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x6Cu, 0x00u, 0x6Fu,
+      0x00u, 0x67u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u,
+      0x00u, 0x10u, 0x00u, 0x00u, 0x25u, 0x3Du, 0x8Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x0Cu,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x69u, 0x00u, 0x72u, 0x00u, 0x63u, 0x00u,
+      0x4Fu, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x6Cu, 0x00u, 0x61u,
+      0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Du, 0x00u, 0x65u,
+      0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u,
+      0x41u, 0x00u, 0x77u, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u,
+      0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x54u, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x00u, 0x25u, 0x3Du, 0x8Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u,
+      0x77u, 0x00u, 0x68u, 0x00u, 0x6Fu, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u,
+      0x76u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x70u, 0x00u, 0x6Cu, 0x00u,
+      0x79u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x73u,
+      0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x48u, 0x00u, 0x6Fu, 0x00u, 0x73u, 0x00u, 0x74u,
+      0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x65u, 0x00u,
+      0x6Eu, 0x00u, 0x63u, 0x00u, 0x72u, 0x00u, 0x79u, 0x00u, 0x70u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u,
+      0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x63u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u,
+      0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x4Du,
+      0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u,
+    ),
+    matcher = ::MapMatcher
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MessageSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MessageSerializerTest.kt
index e9d770d..13918e8 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MessageSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MessageSerializerTest.kt
@@ -34,9 +34,11 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import org.threeten.bp.Instant
 
+@Tag("QuasselSerializerTest")
 class MessageSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MsgIdSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MsgIdSerializerTest.kt
index 03b58bc..0457be7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MsgIdSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/MsgIdSerializerTest.kt
@@ -24,8 +24,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class MsgIdSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkIdSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkIdSerializerTest.kt
index 33e9f22..2b90d5b 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkIdSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkIdSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class NetworkIdSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
new file mode 100644
index 0000000..9f28cd6
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/NetworkInfoSerializerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.quassel
+
+import de.justjanne.libquassel.protocol.models.NetworkInfo
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.types.QuasselType
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("QuasselSerializerTest")
+class NetworkInfoSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      NetworkInfoSerializer,
+      QuasselType.NetworkInfo.serializer<NetworkInfo>(),
+    )
+  }
+
+  @Test
+  fun testEmptyMap() = primitiveSerializerTest(
+    NetworkInfoSerializer,
+    NetworkInfo(),
+    byteBufferOf(
+      // no elements
+      0x00u, 0x00u, 0x00u, 0x00u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testNormal() = primitiveSerializerTest(
+    NetworkInfoSerializer,
+    NetworkInfo(
+      networkId = NetworkId(4),
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x19u, 0x00u, 0x00u, 0x00u, 0x12u, 0x00u, 0x4Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u,
+      0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x0Au, 0x4Eu, 0x65u, 0x74u, 0x77u, 0x6Fu, 0x72u, 0x6Bu, 0x49u, 0x64u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x04u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x4Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u,
+      0x72u, 0x00u, 0x6Bu, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu,
+      0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x0Bu, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x49u, 0x64u, 0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu,
+      0x00u, 0x00u, 0x00u, 0x24u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x43u, 0x00u, 0x75u, 0x00u, 0x73u,
+      0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u,
+      0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x1Cu, 0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u,
+      0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u, 0x00u, 0x20u,
+      0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu, 0x00u, 0x72u,
+      0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u,
+      0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u,
+      0x00u, 0x20u, 0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu,
+      0x00u, 0x72u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+      0x00u, 0x67u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u,
+      0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u,
+      0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u,
+      0x6Eu, 0x00u, 0x64u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x50u, 0x00u,
+      0x65u, 0x00u, 0x72u, 0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Du, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x41u,
+      0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u,
+      0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u,
+      0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu,
+      0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u,
+      0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x28u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u,
+      0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u,
+      0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x53u,
+      0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u,
+      0x00u, 0x53u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x63u, 0x00u, 0x6Fu,
+      0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x18u, 0x00u, 0x53u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u,
+      0x73u, 0x00u, 0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x41u,
+      0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu,
+      0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x01u, 0x00u, 0x00u,
+      0x00u, 0x2Au, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u,
+      0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu,
+      0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x03u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+      0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+      0x63u, 0x00u, 0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u,
+      0x73u, 0x00u, 0x00u, 0x00u, 0x85u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x32u, 0x00u, 0x55u, 0x00u, 0x6Eu,
+      0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x52u,
+      0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u,
+      0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u,
+      0x00u, 0x01u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x6Fu,
+      0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u,
+      0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x55u,
+      0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x43u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x6Du,
+      0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u,
+      0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u,
+      0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u,
+      0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x42u, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x74u,
+      0x00u, 0x53u, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u,
+      0x67u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u,
+      0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x28u, 0x00u, 0x55u, 0x00u, 0x6Eu, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u,
+      0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u,
+      0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/PeerPtrSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/PeerPtrSerializerTest.kt
index 9659e02..79ae4f8 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/PeerPtrSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/PeerPtrSerializerTest.kt
@@ -23,8 +23,10 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+@Tag("QuasselSerializerTest")
 class PeerPtrSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/QHostAddressSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/QHostAddressSerializerTest.kt
index d938356..b39640d 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/QHostAddressSerializerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/quassel/QHostAddressSerializerTest.kt
@@ -22,11 +22,13 @@ import de.justjanne.libquassel.protocol.models.types.QuasselType
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.primitiveSerializerTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 import java.net.Inet4Address
 import java.net.Inet6Address
 import java.net.InetAddress
 
+@Tag("QuasselSerializerTest")
 class QHostAddressSerializerTest {
   @Test
   fun testIsRegistered() {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializerTest.kt
new file mode 100644
index 0000000..025272b
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatReplySerializerTest.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+import org.threeten.bp.Instant
+
+@Tag("SignalProxySerializerTest")
+class HeartBeatReplySerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeatReply(
+      Instant.EPOCH
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // HeartBeatReply
+      0x00u, 0x00u, 0x00u, 0x06u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeatReply(
+      Instant.EPOCH
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x00u, 0x25u, 0x3Du, 0x8Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u,
+    )
+  )
+
+  @Test
+  fun testRealistic() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeatReply(
+      Instant.ofEpochMilli(1614520296337)
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x06u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x00u, 0x25u, 0x86u, 0x8Au, 0x02u, 0xF9u, 0x5Bu, 0x91u, 0x02u,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializerTest.kt
new file mode 100644
index 0000000..188393b
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/HeartBeatSerializerTest.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+import org.threeten.bp.Instant
+
+@Tag("SignalProxySerializerTest")
+class HeartBeatSerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeat(
+      Instant.EPOCH
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // HeartBeat
+      0x00u, 0x00u, 0x00u, 0x05u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeat(
+      Instant.EPOCH
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x00u, 0x25u, 0x3Du, 0x8Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u,
+    )
+  )
+
+  @Test
+  fun testRealistic() = signalProxySerializerTest(
+    SignalProxyMessage.HeartBeat(
+      Instant.ofEpochMilli(1614520296337)
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u,
+      0x10u, 0x00u, 0x00u, 0x25u, 0x86u, 0x8Au, 0x02u, 0xF9u, 0x5Bu, 0x91u, 0x02u,
+    )
+  )
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializerTest.kt
new file mode 100644
index 0000000..593f248
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitDataSerializerTest.kt
@@ -0,0 +1,183 @@
+/*
+ * 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.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.syncables.Network
+import de.justjanne.libquassel.protocol.syncables.state.NetworkState
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("SignalProxySerializerTest")
+class InitDataSerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.InitData(
+      className = "",
+      objectName = "",
+      initData = emptyMap()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // Rpc
+      0x00u, 0x00u, 0x00u, 0x04u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.InitData(
+      className = "",
+      objectName = "",
+      initData = emptyMap()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() {
+    signalProxySerializerTest(
+      SignalProxyMessage.InitData(
+        className = "Network",
+        objectName = "4",
+        initData = Network(
+          state = NetworkState(
+            networkId = NetworkId(4)
+          )
+        ).toVariantMap()
+      ),
+      byteBufferOf(
+        0x00u, 0x00u, 0x00u, 0x45u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Eu, 0x65u, 0x74u, 0x77u, 0x6Fu, 0x72u, 0x6Bu, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x34u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u,
+        0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Bu, 0x00u, 0x4Eu,
+        0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u,
+        0x3Cu, 0x00u, 0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x69u, 0x00u,
+        0x74u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u,
+        0x3Eu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x63u, 0x00u, 0x75u, 0x00u, 0x72u,
+        0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u,
+        0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x6Du, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x69u, 0x00u, 0x63u,
+        0x00u, 0x6Bu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x63u,
+        0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u,
+        0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u,
+        0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u,
+        0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u,
+        0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u,
+        0x64u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u,
+        0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x63u,
+        0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x44u,
+        0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x67u, 0x00u, 0x00u,
+        0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u, 0x00u, 0x0Au,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u,
+        0x69u, 0x00u, 0x74u, 0x00u, 0x79u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x0Bu, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x49u, 0x64u, 0x00u, 0xFFu, 0xFFu, 0xFFu,
+        0xFFu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x43u,
+        0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u,
+        0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u,
+        0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u,
+        0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x53u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u,
+        0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u,
+        0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x6Fu, 0x00u,
+        0x6Du, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u, 0x00u,
+        0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x70u, 0x00u, 0x65u,
+        0x00u, 0x72u, 0x00u, 0x66u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Du, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x75u, 0x00u, 0x73u,
+        0x00u, 0x65u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u,
+        0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+        0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u,
+        0x79u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x65u, 0x00u,
+        0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x28u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u,
+        0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u,
+        0x73u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u,
+        0x65u, 0x00u, 0x53u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu,
+        0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x00u,
+        0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u,
+        0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u,
+        0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u,
+        0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu,
+        0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x2Au, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+        0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+        0x63u, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u,
+        0x61u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x00u, 0x3Cu, 0x00u, 0x00u, 0x00u, 0x0Au,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u,
+        0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u,
+        0x52u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+        0x85u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x32u, 0x00u, 0x75u, 0x00u,
+        0x6Eu, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u,
+        0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u,
+        0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u,
+        0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Cu, 0x00u, 0x72u,
+        0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x6Fu, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u,
+        0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u,
+        0x43u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u,
+        0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+        0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u,
+        0x00u, 0x6Du, 0x00u, 0x73u, 0x00u, 0x67u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x42u,
+        0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x53u, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u,
+        0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x26u, 0x00u, 0x6Du, 0x00u, 0x73u, 0x00u, 0x67u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u,
+        0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x44u,
+        0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x08u,
+        0x98u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u, 0x6Cu,
+        0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x4Du, 0x00u, 0x65u,
+        0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u,
+        0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x10u, 0x00u, 0x73u, 0x00u, 0x6Bu, 0x00u, 0x69u, 0x00u, 0x70u, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u,
+        0x73u, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x10u, 0x00u, 0x53u, 0x00u, 0x75u, 0x00u, 0x70u, 0x00u, 0x70u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+        0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u,
+        0x72u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u,
+        0x70u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x73u, 0x00u, 0x45u, 0x00u,
+        0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x49u, 0x00u,
+        0x72u, 0x00u, 0x63u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x41u, 0x00u,
+        0x6Eu, 0x00u, 0x64u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+        0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x0Au,
+        0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u,
+        0x6Eu, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      )
+    )
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializerTest.kt
new file mode 100644
index 0000000..b2c52a2
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/InitRequestSerializerTest.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.justjanne.libquassel.protocol.serializers.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("SignalProxySerializerTest")
+class InitRequestSerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.InitRequest(
+      className = "",
+      objectName = ""
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // Rpc
+      0x00u, 0x00u, 0x00u, 0x03u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.InitRequest(
+      className = "",
+      objectName = ""
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() {
+    signalProxySerializerTest(
+      SignalProxyMessage.InitRequest(
+        className = "Network",
+        objectName = "4"
+      ),
+      byteBufferOf(
+        0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Eu, 0x65u, 0x74u, 0x77u, 0x6Fu, 0x72u, 0x6Bu, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x34u,
+      )
+    )
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
new file mode 100644
index 0000000..7dbd8d7
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/RpcSerializerTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.models.types.QuasselType
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import de.justjanne.libquassel.protocol.variant.QVariant_
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("SignalProxySerializerTest")
+class RpcSerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.Rpc(
+      slotName = "",
+      params = emptyList()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // Rpc
+      0x00u, 0x00u, 0x00u, 0x02u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.Rpc(
+      slotName = "",
+      params = emptyList()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() {
+    signalProxySerializerTest(
+      SignalProxyMessage.Rpc(
+        slotName = "2createIdentity(Identity,QVariantMap)",
+        params = listOf(
+          qVariant(
+            emptyMap(),
+            QuasselType.Identity
+          ),
+          qVariant(
+            emptyMap<String, QVariant_>(),
+            QtType.QVariantMap
+          )
+        )
+      ),
+      byteBufferOf(
+        0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x25u, 0x32u, 0x63u, 0x72u, 0x65u, 0x61u, 0x74u, 0x65u, 0x49u, 0x64u, 0x65u,
+        0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x28u, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x2Cu, 0x51u,
+        0x56u, 0x61u, 0x72u, 0x69u, 0x61u, 0x6Eu, 0x74u, 0x4Du, 0x61u, 0x70u, 0x29u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x09u, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      )
+    )
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializerTest.kt
new file mode 100644
index 0000000..4e934dc
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/signalproxy/SyncSerializerTest.kt
@@ -0,0 +1,187 @@
+/*
+ * 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.signalproxy
+
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.syncables.Network
+import de.justjanne.libquassel.protocol.syncables.state.NetworkState
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.signalProxySerializerTest
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+@Tag("SignalProxySerializerTest")
+class SyncSerializerTest {
+  @Test
+  fun testEmptyMap() = signalProxySerializerTest(
+    SignalProxyMessage.Sync(
+      className = "",
+      objectName = "",
+      slotName = "",
+      params = emptyList()
+    ),
+    byteBufferOf(
+      // 4 elements
+      0x00u, 0x00u, 0x00u, 0x01u,
+      // int
+      0x00u, 0x00u, 0x00u, 0x02u,
+      0x00u,
+      // Sync
+      0x00u, 0x00u, 0x00u, 0x01u,
+    ),
+    featureSets = emptyList(),
+    serializeFeatureSet = null
+  )
+
+  @Test
+  fun testSimple() = signalProxySerializerTest(
+    SignalProxyMessage.Sync(
+      className = "",
+      objectName = "",
+      slotName = "",
+      params = emptyList()
+    ),
+    byteBufferOf(
+      0x00u, 0x00u, 0x00u, 0x04u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u,
+      0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+      0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    )
+  )
+
+  @Test
+  fun testRealistic() {
+
+    signalProxySerializerTest(
+      SignalProxyMessage.Sync(
+        className = "Network",
+        objectName = "4",
+        slotName = "update",
+        params = listOf(
+          qVariant(
+            Network(
+              state = NetworkState(
+                networkId = NetworkId(4)
+              )
+            ).toVariantMap(),
+            QtType.QVariantMap
+          )
+        )
+      ),
+      byteBufferOf(
+        0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x07u, 0x4Eu, 0x65u, 0x74u, 0x77u, 0x6Fu, 0x72u, 0x6Bu, 0x00u, 0x00u, 0x00u,
+        0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x01u, 0x34u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x06u,
+        0x75u, 0x70u, 0x64u, 0x61u, 0x74u, 0x65u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x21u, 0x00u,
+        0x00u, 0x00u, 0x16u, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x77u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u,
+        0x6Bu, 0x00u, 0x4Eu, 0x00u, 0x61u, 0x00u, 0x6Du, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x22u, 0x00u, 0x3Cu, 0x00u, 0x6Eu, 0x00u, 0x6Fu, 0x00u, 0x74u, 0x00u, 0x20u, 0x00u, 0x69u, 0x00u, 0x6Eu,
+        0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u,
+        0x00u, 0x64u, 0x00u, 0x3Eu, 0x00u, 0x00u, 0x00u, 0x1Au, 0x00u, 0x63u, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u, 0x72u,
+        0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u,
+        0x00u, 0x72u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u,
+        0x6Du, 0x00u, 0x79u, 0x00u, 0x4Eu, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u, 0x6Bu, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u,
+        0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x79u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x1Cu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u,
+        0x6Fu, 0x00u, 0x72u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u,
+        0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u, 0x00u, 0x00u,
+        0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u, 0x6Fu, 0x00u,
+        0x72u, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u,
+        0x67u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu, 0x38u, 0x00u,
+        0x00u, 0x00u, 0x20u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x46u, 0x00u,
+        0x6Fu, 0x00u, 0x72u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x64u, 0x00u, 0x69u, 0x00u,
+        0x6Eu, 0x00u, 0x67u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x05u, 0x55u, 0x54u, 0x46u, 0x5Fu,
+        0x38u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x69u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u,
+        0x69u, 0x00u, 0x74u, 0x00u, 0x79u, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x7Fu, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x0Bu, 0x49u, 0x64u, 0x65u, 0x6Eu, 0x74u, 0x69u, 0x74u, 0x79u, 0x49u, 0x64u, 0x00u, 0xFFu, 0xFFu, 0xFFu,
+        0xFFu, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x43u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+        0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+        0x63u, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x53u, 0x00u, 0x74u, 0x00u, 0x61u, 0x00u,
+        0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x1Eu,
+        0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x6Fu,
+        0x00u, 0x6Du, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x00u,
+        0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0Eu, 0x00u, 0x70u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x66u,
+        0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x6Du, 0x00u, 0x00u, 0x00u, 0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x1Eu, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+        0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u, 0x66u, 0x00u,
+        0x79u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u,
+        0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x69u, 0x00u,
+        0x66u, 0x00u, 0x79u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u, 0x69u, 0x00u, 0x63u, 0x00u,
+        0x65u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x61u,
+        0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x49u, 0x00u, 0x64u, 0x00u, 0x65u, 0x00u, 0x6Eu, 0x00u, 0x74u,
+        0x00u, 0x69u, 0x00u, 0x66u, 0x00u, 0x79u, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u,
+        0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x0Eu, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x53u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u,
+        0x6Cu, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u,
+        0x73u, 0x00u, 0x6Cu, 0x00u, 0x41u, 0x00u, 0x63u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u,
+        0x74u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x18u, 0x00u, 0x73u,
+        0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x6Cu, 0x00u, 0x50u, 0x00u, 0x61u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x77u,
+        0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x20u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x41u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u,
+        0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u,
+        0x63u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x2Au, 0x00u, 0x61u, 0x00u,
+        0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u,
+        0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x49u, 0x00u, 0x6Eu, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u,
+        0x72u, 0x00u, 0x76u, 0x00u, 0x61u, 0x00u, 0x6Cu, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x00u, 0x3Cu,
+        0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x61u, 0x00u, 0x75u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x52u, 0x00u, 0x65u,
+        0x00u, 0x63u, 0x00u, 0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x52u,
+        0x00u, 0x65u, 0x00u, 0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x85u,
+        0x00u, 0x00u, 0x0Au, 0x00u, 0x00u, 0x00u, 0x32u, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u, 0x6Cu, 0x00u, 0x69u, 0x00u,
+        0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u,
+        0x6Fu, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x63u, 0x00u, 0x74u, 0x00u, 0x52u, 0x00u, 0x65u, 0x00u,
+        0x74u, 0x00u, 0x72u, 0x00u, 0x69u, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x1Cu, 0x00u, 0x72u, 0x00u, 0x65u, 0x00u, 0x6Au, 0x00u, 0x6Fu, 0x00u, 0x69u, 0x00u, 0x6Eu, 0x00u,
+        0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u,
+        0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u,
+        0x43u, 0x00u, 0x75u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x6Fu, 0x00u, 0x6Du, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u,
+        0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u,
+        0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x6Du, 0x00u, 0x73u, 0x00u,
+        0x67u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x42u, 0x00u, 0x75u, 0x00u, 0x72u, 0x00u,
+        0x73u, 0x00u, 0x74u, 0x00u, 0x53u, 0x00u, 0x69u, 0x00u, 0x7Au, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x03u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x05u, 0x00u, 0x00u, 0x00u, 0x26u, 0x00u, 0x6Du, 0x00u, 0x73u, 0x00u, 0x67u, 0x00u, 0x52u,
+        0x00u, 0x61u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x4Du, 0x00u, 0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u,
+        0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x44u, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x61u, 0x00u, 0x79u, 0x00u, 0x00u,
+        0x00u, 0x03u, 0x00u, 0x00u, 0x00u, 0x08u, 0x98u, 0x00u, 0x00u, 0x00u, 0x28u, 0x00u, 0x75u, 0x00u, 0x6Eu, 0x00u,
+        0x6Cu, 0x00u, 0x69u, 0x00u, 0x6Du, 0x00u, 0x69u, 0x00u, 0x74u, 0x00u, 0x65u, 0x00u, 0x64u, 0x00u, 0x4Du, 0x00u,
+        0x65u, 0x00u, 0x73u, 0x00u, 0x73u, 0x00u, 0x61u, 0x00u, 0x67u, 0x00u, 0x65u, 0x00u, 0x52u, 0x00u, 0x61u, 0x00u,
+        0x74u, 0x00u, 0x65u, 0x00u, 0x00u, 0x00u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x73u, 0x00u,
+        0x6Bu, 0x00u, 0x69u, 0x00u, 0x70u, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+        0x0Bu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x53u, 0x00u, 0x75u, 0x00u, 0x70u,
+        0x00u, 0x70u, 0x00u, 0x6Fu, 0x00u, 0x72u, 0x00u, 0x74u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x14u, 0x00u, 0x53u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x76u, 0x00u,
+        0x65u, 0x00u, 0x72u, 0x00u, 0x4Cu, 0x00u, 0x69u, 0x00u, 0x73u, 0x00u, 0x74u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u,
+        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x43u, 0x00u, 0x61u, 0x00u, 0x70u, 0x00u, 0x73u,
+        0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x16u, 0x00u, 0x43u, 0x00u,
+        0x61u, 0x00u, 0x70u, 0x00u, 0x73u, 0x00u, 0x45u, 0x00u, 0x6Eu, 0x00u, 0x61u, 0x00u, 0x62u, 0x00u, 0x6Cu, 0x00u,
+        0x65u, 0x00u, 0x64u, 0x00u, 0x00u, 0x00u, 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x26u,
+        0x00u, 0x49u, 0x00u, 0x72u, 0x00u, 0x63u, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u,
+        0x00u, 0x41u, 0x00u, 0x6Eu, 0x00u, 0x64u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u, 0x00u, 0x6Eu, 0x00u, 0x6Eu,
+        0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x02u, 0x00u,
+        0x00u, 0x00u, 0x0Au, 0x00u, 0x55u, 0x00u, 0x73u, 0x00u, 0x65u, 0x00u, 0x72u, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u,
+        0x08u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x00u, 0x43u, 0x00u, 0x68u, 0x00u, 0x61u,
+        0x00u, 0x6Eu, 0x00u, 0x6Eu, 0x00u, 0x65u, 0x00u, 0x6Cu, 0x00u, 0x73u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u,
+        0x00u, 0x00u, 0x00u,
+      )
+    )
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkTest.kt
new file mode 100644
index 0000000..75226e0
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/NetworkTest.kt
@@ -0,0 +1,104 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.syncables
+
+import de.justjanne.libquassel.protocol.models.NetworkServer
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.syncables.state.NetworkState
+import de.justjanne.libquassel.protocol.testutil.nextEnum
+import de.justjanne.libquassel.protocol.testutil.nextIrcChannel
+import de.justjanne.libquassel.protocol.testutil.nextIrcUser
+import de.justjanne.libquassel.protocol.testutil.nextString
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import kotlin.random.Random
+import kotlin.random.nextUInt
+
+class NetworkTest {
+  @Test
+  fun testSerialization() {
+    val random = Random(1337)
+    val networkId = NetworkId(random.nextInt())
+    val expected = random.nextNetwork(networkId)
+
+    val actual = Network(state = NetworkState(networkId = networkId)).apply {
+      fromVariantMap(Network(state = expected).toVariantMap())
+    }.state()
+
+    assertEquals(expected, actual)
+  }
+}
+
+fun Random.nextNetwork(networkId: NetworkId) = NetworkState(
+  networkId = networkId,
+  identity = IdentityId(nextInt()),
+  myNick = nextString(),
+  latency = nextInt(),
+  networkName = nextString(),
+  currentServer = nextString(),
+  connected = nextBoolean(),
+  connectionState = nextEnum(),
+  ircUsers = List(nextInt(20)) {
+    nextIrcUser(networkId)
+  }.associateBy(IrcUser::nick),
+  ircChannels = List(nextInt(20)) {
+    nextIrcChannel(networkId)
+  }.associateBy(IrcChannel::name),
+  supports = List(nextInt(20)) {
+    nextString() to nextString()
+  }.toMap(),
+  caps = List(nextInt(20)) {
+    nextString() to nextString()
+  }.toMap(),
+  capsEnabled = List(nextInt(20)) {
+    nextString()
+  }.toSet(),
+  serverList =  List(nextInt(20)) {
+    nextNetworkServer()
+  },
+  useRandomServer = nextBoolean(),
+  perform =  List(nextInt(20)) {
+    nextString()
+  },
+  useAutoIdentify = nextBoolean(),
+  autoIdentifyService = nextString(),
+  autoIdentifyPassword = nextString(),
+  useSasl = nextBoolean(),
+  saslAccount = nextString(),
+  saslPassword = nextString(),
+  useAutoReconnect = nextBoolean(),
+  autoReconnectInterval = nextUInt(),
+  autoReconnectRetries = nextUInt(UShort.MAX_VALUE.toUInt()).toUShort(),
+  unlimitedReconnectRetries = nextBoolean(),
+  rejoinChannels = nextBoolean(),
+  useCustomMessageRate = nextBoolean(),
+  messageRateBurstSize = nextUInt(),
+  messageRateDelay = nextUInt(),
+  codecForServer = nextString(),
+  codecForEncoding = nextString(),
+  codecForDecoding = nextString()
+)
+
+fun Random.nextNetworkServer() = NetworkServer(
+  host = nextString(),
+  port = nextUInt(),
+  password = nextString(),
+  useSsl = nextBoolean(),
+  sslVerify = nextBoolean(),
+  sslVersion = nextInt(),
+  useProxy = nextBoolean(),
+  proxyType = nextEnum(),
+  proxyHost = nextString(),
+  proxyPort = nextUInt(),
+  proxyUser = nextString(),
+  proxyPass = nextString()
+)
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
new file mode 100644
index 0000000..29f8612
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
@@ -0,0 +1,75 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.testutil
+
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.syncables.IrcChannel
+import de.justjanne.libquassel.protocol.syncables.IrcUser
+import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
+import de.justjanne.libquassel.protocol.syncables.state.IrcUserState
+import org.threeten.bp.Instant
+import java.util.EnumSet
+import java.util.UUID
+import kotlin.random.Random
+
+fun Random.nextString(): String {
+  return UUID(nextLong(), nextLong()).toString()
+}
+
+fun <T> Random.nextOf(elements: Collection<T>): T {
+  val index = nextInt(elements.size)
+  return elements.drop(index).first()
+}
+
+fun <T> Random.nextOf(vararg elements: T): T {
+  return nextOf(elements.toList())
+}
+
+inline fun <reified T: Enum<T>> Random.nextEnum(): T {
+  return nextOf(EnumSet.allOf(T::class.java).toList())
+}
+
+fun Random.nextInstant(): Instant = Instant.ofEpochMilli(nextLong())
+
+fun Random.nextIrcUser(
+  networkId: NetworkId = NetworkId(nextInt())
+) = IrcUser(
+  state = IrcUserState(
+    network = networkId,
+    nick = nextString(),
+    user = nextString(),
+    host = nextString(),
+    realName = nextString(),
+    account = nextString(),
+    away = nextBoolean(),
+    awayMessage = nextString(),
+    idleTime = nextInstant(),
+    loginTime = nextInstant(),
+    server = nextString(),
+    ircOperator = nextString(),
+    lastAwayMessageTime = nextInstant(),
+    whoisServiceReply = nextString(),
+    suserHost = nextString(),
+    encrypted = nextBoolean()
+  )
+)
+
+fun Random.nextIrcChannel(
+  networkId: NetworkId = NetworkId(nextInt())
+) = IrcChannel(
+  state = IrcChannelState(
+    network = networkId,
+    name = nextString(),
+    topic = nextString(),
+    password = nextString(),
+    encrypted = nextBoolean()
+  )
+)
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 85266a8..d20a0e2 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,6 +19,7 @@
 package de.justjanne.libquassel.protocol.testutil
 
 import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.contentToString
 import de.justjanne.libquassel.protocol.io.useChainedByteBuffer
 import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.serializers.HandshakeMessageSerializer
@@ -26,8 +27,10 @@ import de.justjanne.libquassel.protocol.testutil.matchers.ByteBufferMatcher
 import de.justjanne.libquassel.protocol.util.withRewind
 import org.hamcrest.Matcher
 import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
 import java.nio.ByteBuffer
-import kotlin.test.assertEquals
 
 inline fun <reified T : HandshakeMessage> handshakeSerializerTest(
   value: T,
@@ -43,7 +46,7 @@ inline fun <reified T : HandshakeMessage> handshakeSerializerTest(
       if (matcher != null) {
         assertThat(after, matcher(value))
       } else {
-        assertEquals(after, value)
+        assertEquals(value, after)
       }
     }
     if (serializeFeatureSet != null) {
@@ -61,9 +64,10 @@ inline fun <reified T : HandshakeMessage> handshakeSerializerTest(
         HandshakeMessageSerializer.serialize(it, value, featureSet)
       },
       featureSet
-    ) as? T
+    )
+    assertEquals(T::class.java, after::class.java)
     if (matcher != null) {
-      assertThat(after, matcher(value))
+      assertThat(after as? T, matcher(value))
     } else {
       assertEquals(value, after)
     }
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
index 782d6a5..8c64d8f 100644
--- 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
@@ -19,6 +19,7 @@
 package de.justjanne.libquassel.protocol.testutil
 
 import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.contentToString
 import de.justjanne.libquassel.protocol.io.useChainedByteBuffer
 import de.justjanne.libquassel.protocol.models.SignalProxyMessage
 import de.justjanne.libquassel.protocol.serializers.SignalProxyMessageSerializer
@@ -26,8 +27,8 @@ import de.justjanne.libquassel.protocol.testutil.matchers.ByteBufferMatcher
 import de.justjanne.libquassel.protocol.util.withRewind
 import org.hamcrest.Matcher
 import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Assertions.assertEquals
 import java.nio.ByteBuffer
-import kotlin.test.assertEquals
 
 inline fun <reified T : SignalProxyMessage> signalProxySerializerTest(
   value: T,
@@ -43,7 +44,7 @@ inline fun <reified T : SignalProxyMessage> signalProxySerializerTest(
       if (matcher != null) {
         assertThat(after, matcher(value))
       } else {
-        assertEquals(after, value)
+        assertEquals(value, after)
       }
     }
     if (serializeFeatureSet != null) {
@@ -59,11 +60,15 @@ inline fun <reified T : SignalProxyMessage> signalProxySerializerTest(
     val after = SignalProxyMessageSerializer.deserialize(
       useChainedByteBuffer {
         SignalProxyMessageSerializer.serialize(it, value, featureSet)
+        if (encoded == null) {
+          println(it.toBuffer().contentToString())
+        }
       },
       featureSet
-    ) as? T
+    )
+    assertEquals(T::class.java, after::class.java)
     if (matcher != null) {
-      assertThat(after, matcher(value))
+      assertThat(after as? T, matcher(value))
     } else {
       assertEquals(value, after)
     }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testPrimitiveSerializerDirect.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testPrimitiveSerializerDirect.kt
index 186c429..7c9709d 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testPrimitiveSerializerDirect.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/testPrimitiveSerializerDirect.kt
@@ -35,7 +35,6 @@ fun <T> testPrimitiveSerializerDirect(
   val buffer = ChainedByteBuffer(limit = 16384)
   serializer.serialize(buffer, data, featureSet)
   val result = buffer.toBuffer()
-  println(result.contentToString())
   val after = serializer.deserialize(result, featureSet)
   assertEquals(0, result.remaining())
   if (matcher != null) {
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/types/SignedIdTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/types/SignedIdTest.kt
index 63c9b25..66bdb6d 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/types/SignedIdTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/types/SignedIdTest.kt
@@ -33,33 +33,121 @@ class SignedIdTest {
   @Test
   fun testNegativeOne() {
     assertFalse(BufferId(-1).isValid())
+    assertFalse(SignedIdProxy.isValidId(BufferId(-1)))
     assertFalse(IdentityId(-1).isValid())
+    assertFalse(SignedIdProxy.isValidId(IdentityId(-1)))
     assertFalse(MsgId(-1).isValid())
+    assertFalse(SignedIdProxy.isValidId64(MsgId(-1)))
     assertFalse(NetworkId(-1).isValid())
+    assertFalse(SignedIdProxy.isValidId(NetworkId(-1)))
+
+    assertEquals("BufferId(-1)", BufferId(-1).toString())
+    assertEquals("BufferId(-1)", SignedIdProxy.toString(BufferId(-1)))
+    assertEquals("IdentityId(-1)", IdentityId(-1).toString())
+    assertEquals("IdentityId(-1)", SignedIdProxy.toString(IdentityId(-1)))
+    assertEquals("MsgId(-1)", MsgId(-1).toString())
+    assertEquals("MsgId(-1)", SignedIdProxy.toString(MsgId(-1)))
+    assertEquals("NetworkId(-1)", NetworkId(-1).toString())
+    assertEquals("NetworkId(-1)", SignedIdProxy.toString(NetworkId(-1)))
+
+    assertEquals((-1).hashCode(), BufferId(-1).hashCode())
+    assertEquals((-1).hashCode(), SignedIdProxy.hashCode(BufferId(-1)))
+    assertEquals((-1).hashCode(), IdentityId(-1).hashCode())
+    assertEquals((-1).hashCode(), SignedIdProxy.hashCode(IdentityId(-1)))
+    assertEquals((-1L).hashCode(), MsgId(-1).hashCode())
+    assertEquals((-1L).hashCode(), SignedIdProxy.hashCode(MsgId(-1)))
+    assertEquals((-1).hashCode(), NetworkId(-1).hashCode())
+    assertEquals((-1).hashCode(), SignedIdProxy.hashCode(NetworkId(-1)))
   }
 
   @Test
   fun testZero() {
     assertFalse(BufferId(0).isValid())
+    assertFalse(SignedIdProxy.isValidId(BufferId(0)))
     assertFalse(IdentityId(0).isValid())
+    assertFalse(SignedIdProxy.isValidId(IdentityId(0)))
     assertFalse(MsgId(0).isValid())
+    assertFalse(SignedIdProxy.isValidId64(MsgId(0)))
     assertFalse(NetworkId(0).isValid())
+    assertFalse(SignedIdProxy.isValidId(NetworkId(0)))
+
+    assertEquals("BufferId(0)", BufferId(0).toString())
+    assertEquals("BufferId(0)", SignedIdProxy.toString(BufferId(0)))
+    assertEquals("IdentityId(0)", IdentityId(0).toString())
+    assertEquals("IdentityId(0)", SignedIdProxy.toString(IdentityId(0)))
+    assertEquals("MsgId(0)", MsgId(0).toString())
+    assertEquals("MsgId(0)", SignedIdProxy.toString(MsgId(0)))
+    assertEquals("NetworkId(0)", NetworkId(0).toString())
+    assertEquals("NetworkId(0)", SignedIdProxy.toString(NetworkId(0)))
+
+    assertEquals(0.hashCode(), BufferId(0).hashCode())
+    assertEquals(0.hashCode(), SignedIdProxy.hashCode(BufferId(0)))
+    assertEquals(0.hashCode(), IdentityId(0).hashCode())
+    assertEquals(0.hashCode(), SignedIdProxy.hashCode(IdentityId(0)))
+    assertEquals(0.hashCode(), MsgId(0).hashCode())
+    assertEquals(0.hashCode(), SignedIdProxy.hashCode(MsgId(0)))
+    assertEquals(0.hashCode(), NetworkId(0).hashCode())
+    assertEquals(0.hashCode(), SignedIdProxy.hashCode(NetworkId(0)))
   }
 
   @Test
   fun testMinimal() {
     assertFalse(BufferId(Int.MIN_VALUE).isValid())
+    assertFalse(SignedIdProxy.isValidId(BufferId(Int.MIN_VALUE)))
     assertFalse(IdentityId(Int.MIN_VALUE).isValid())
+    assertFalse(SignedIdProxy.isValidId(IdentityId(Int.MIN_VALUE)))
     assertFalse(MsgId(Long.MIN_VALUE).isValid())
+    assertFalse(SignedIdProxy.isValidId64(MsgId(Long.MIN_VALUE)))
     assertFalse(NetworkId(Int.MIN_VALUE).isValid())
+    assertFalse(SignedIdProxy.isValidId(NetworkId(Int.MIN_VALUE)))
+
+    assertEquals("BufferId(-2147483648)", BufferId(Int.MIN_VALUE).toString())
+    assertEquals("BufferId(-2147483648)", SignedIdProxy.toString(BufferId(Int.MIN_VALUE)))
+    assertEquals("IdentityId(-2147483648)", IdentityId(Int.MIN_VALUE).toString())
+    assertEquals("IdentityId(-2147483648)", SignedIdProxy.toString(IdentityId(Int.MIN_VALUE)))
+    assertEquals("MsgId(-9223372036854775808)", MsgId(Long.MIN_VALUE).toString())
+    assertEquals("MsgId(-9223372036854775808)", SignedIdProxy.toString(MsgId(Long.MIN_VALUE)))
+    assertEquals("NetworkId(-2147483648)", NetworkId(Int.MIN_VALUE).toString())
+    assertEquals("NetworkId(-2147483648)", SignedIdProxy.toString(NetworkId(Int.MIN_VALUE)))
+
+    assertEquals(Int.MIN_VALUE.hashCode(), BufferId(Int.MIN_VALUE).hashCode())
+    assertEquals(Int.MIN_VALUE.hashCode(), SignedIdProxy.hashCode(BufferId(Int.MIN_VALUE)))
+    assertEquals(Int.MIN_VALUE.hashCode(), IdentityId(Int.MIN_VALUE).hashCode())
+    assertEquals(Int.MIN_VALUE.hashCode(), SignedIdProxy.hashCode(IdentityId(Int.MIN_VALUE)))
+    assertEquals(Long.MIN_VALUE.hashCode(), MsgId(Long.MIN_VALUE).hashCode())
+    assertEquals(Long.MIN_VALUE.hashCode(), SignedIdProxy.hashCode(MsgId(Long.MIN_VALUE)))
+    assertEquals(Int.MIN_VALUE.hashCode(), NetworkId(Int.MIN_VALUE).hashCode())
+    assertEquals(Int.MIN_VALUE.hashCode(), SignedIdProxy.hashCode(NetworkId(Int.MIN_VALUE)))
   }
 
   @Test
   fun testMaximum() {
     assertTrue(BufferId(Int.MAX_VALUE).isValid())
+    assertTrue(SignedIdProxy.isValidId(BufferId(Int.MAX_VALUE)))
     assertTrue(IdentityId(Int.MAX_VALUE).isValid())
+    assertTrue(SignedIdProxy.isValidId(IdentityId(Int.MAX_VALUE)))
     assertTrue(MsgId(Long.MAX_VALUE).isValid())
+    assertTrue(SignedIdProxy.isValidId64(MsgId(Long.MAX_VALUE)))
     assertTrue(NetworkId(Int.MAX_VALUE).isValid())
+    assertTrue(SignedIdProxy.isValidId(NetworkId(Int.MAX_VALUE)))
+
+    assertEquals("BufferId(2147483647)", BufferId(Int.MAX_VALUE).toString())
+    assertEquals("BufferId(2147483647)", SignedIdProxy.toString(BufferId(Int.MAX_VALUE)))
+    assertEquals("IdentityId(2147483647)", IdentityId(Int.MAX_VALUE).toString())
+    assertEquals("IdentityId(2147483647)", SignedIdProxy.toString(IdentityId(Int.MAX_VALUE)))
+    assertEquals("MsgId(9223372036854775807)", MsgId(Long.MAX_VALUE).toString())
+    assertEquals("MsgId(9223372036854775807)", SignedIdProxy.toString(MsgId(Long.MAX_VALUE)))
+    assertEquals("NetworkId(2147483647)", NetworkId(Int.MAX_VALUE).toString())
+    assertEquals("NetworkId(2147483647)", SignedIdProxy.toString(NetworkId(Int.MAX_VALUE)))
+
+    assertEquals(Int.MAX_VALUE.hashCode(), BufferId(Int.MAX_VALUE).hashCode())
+    assertEquals(Int.MAX_VALUE.hashCode(), SignedIdProxy.hashCode(BufferId(Int.MAX_VALUE)))
+    assertEquals(Int.MAX_VALUE.hashCode(), IdentityId(Int.MAX_VALUE).hashCode())
+    assertEquals(Int.MAX_VALUE.hashCode(), SignedIdProxy.hashCode(IdentityId(Int.MAX_VALUE)))
+    assertEquals(Long.MAX_VALUE.hashCode(), MsgId(Long.MAX_VALUE).hashCode())
+    assertEquals(Long.MAX_VALUE.hashCode(), SignedIdProxy.hashCode(MsgId(Long.MAX_VALUE)))
+    assertEquals(Int.MAX_VALUE.hashCode(), NetworkId(Int.MAX_VALUE).hashCode())
+    assertEquals(Int.MAX_VALUE.hashCode(), SignedIdProxy.hashCode(NetworkId(Int.MAX_VALUE)))
   }
 
   @Test
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/InsertTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/InsertTest.kt
new file mode 100644
index 0000000..b35d4aa
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/InsertTest.kt
@@ -0,0 +1,66 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.util.collections
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+class InsertTest {
+  @Test
+  fun whenListIsEmptyReturnsSingletonList() {
+    for (i in -1024..1024) {
+      assertEquals(
+        listOf(7),
+        emptyList<Int>().insert(7, i)
+      )
+    }
+  }
+
+  @Test
+  fun prependsForNegativeOrNull() {
+    for (i in -1024..0) {
+      assertEquals(
+        listOf(7, 1, 2, 3),
+        listOf(1, 2, 3).insert(7, i)
+      )
+    }
+  }
+
+  @Test
+  fun appendsForOutOfBounds() {
+    for (i in 3..1024) {
+      assertEquals(
+        listOf(1, 2, 3, 7),
+        listOf(1, 2, 3).insert(7, i)
+      )
+    }
+  }
+
+  @Test
+  fun appendsForNoParameter() {
+    assertEquals(
+      listOf(1, 2, 3, 7),
+      listOf(1, 2, 3).insert(7)
+    )
+  }
+
+  @Test
+  fun isEquivalentToMutableAdd() {
+    for (i in -1024..1024) {
+      val before = listOf(1, 2, 3, 4, 5).shuffled()
+      val afterMutable = before.toMutableList().apply {
+        add(i.coerceIn(0..before.size), 7)
+      }
+      val afterImmutable = before.insert(7, i)
+      assertEquals(afterMutable, afterImmutable)
+    }
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
new file mode 100644
index 0000000..5b16a3b
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
@@ -0,0 +1,55 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.util.collections
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+class MoveTest {
+  @Test
+  fun appendsForOutOfBounds() {
+    for (i in 6..1024) {
+      assertEquals(
+        listOf(1, 2, 3, 4, 5, 7),
+        listOf(1, 2, 7, 3, 4, 5).move(7, i)
+      )
+    }
+  }
+
+  @Test
+  fun appendsForNoParameter() {
+    assertEquals(
+      listOf(1, 2, 3, 4, 5, 7),
+      listOf(1, 2, 7, 3, 4, 5).move(7)
+    )
+  }
+
+  @Test
+  fun prependsForNegativeOrNull() {
+    for (i in -1024..0) {
+      assertEquals(
+        listOf(7, 1, 2, 3, 4, 5),
+        listOf(1, 2, 7, 3, 4, 5).move(7, i)
+      )
+    }
+  }
+
+  @Test
+  fun noopIfUnchanged() {
+    for (i in 0..1024) {
+      val data = listOf(1, 2, 3, 4, 5, 7).shuffled()
+      assertEquals(
+        data,
+        data.move(7, data.indexOf(7))
+      )
+    }
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/PairsTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/PairsTest.kt
new file mode 100644
index 0000000..0b86745
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/PairsTest.kt
@@ -0,0 +1,54 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.util.collections
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+class PairsTest {
+  @Test
+  fun testFunctionality() {
+    val list = (0 until 1024).map {
+      Pair(Math.random(), Math.random())
+    }
+    assertEquals(
+      list,
+      PairsProxy.call(
+        list.flatMap { listOf(it.first, it.second) },
+        ::Pair
+      )
+    )
+    assertEquals(
+      list,
+      list.flatMap { listOf(it.first, it.second) }.pairs()
+    )
+  }
+
+  @Test
+  fun testMalformedPairs() {
+    val list = (0 until 1024).map {
+      Pair(Math.random(), Math.random())
+    }
+    assertEquals(
+      list.subList(0, 256),
+      PairsProxy.call(
+        list.flatMap { listOf(it.first, it.second) }
+          .subList(0, 513),
+        ::Pair
+      )
+    )
+    assertEquals(
+      list.subList(0, 256),
+      list.flatMap { listOf(it.first, it.second) }
+        .subList(0, 513).pairs()
+    )
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/RemoveTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/RemoveTest.kt
new file mode 100644
index 0000000..98285c4
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/RemoveTest.kt
@@ -0,0 +1,28 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ * Copyright (c) 2021 The Quassel Project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.util.collections
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+class RemoveTest {
+  @Test
+  fun isEquivalentToMutableRemove() {
+    for (i in -1024..1024) {
+      val before = listOf(1, 2, 3, 4, 5).shuffled()
+      val afterMutable = before.toMutableList().apply {
+        remove(i)
+      }
+      val afterImmutable = before.remove(i)
+      assertEquals(afterMutable, afterImmutable)
+    }
+  }
+}
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expansion/ExpansionTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expansion/ExpansionTest.kt
index 1e640e5..142a896 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expansion/ExpansionTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expansion/ExpansionTest.kt
@@ -10,8 +10,8 @@
 
 package de.justjanne.libquassel.protocol.util.expansion
 
+import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Test
-import kotlin.test.assertEquals
 
 class ExpansionTest {
   @Test
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expression/ExpressionMatchTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expression/ExpressionMatchTest.kt
index a485e5a..faa0547 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expression/ExpressionMatchTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/expression/ExpressionMatchTest.kt
@@ -90,11 +90,6 @@ class ExpressionMatchTest {
 
   @Test
   fun matchMultiPhrase() {
-    val emptyMatch =
-      ExpressionMatch(
-        "\n\n",
-        ExpressionMatch.MatchMode.MatchMultiPhrase, false
-      )
     // Simple phrases, case-insensitive
     val simpleMatch = ExpressionMatch(
       "test\nOther ",
@@ -118,9 +113,6 @@ class ExpressionMatchTest {
       false
     )
 
-    println(simpleMatch.positiveRegex)
-    println(simpleMatch.negativeRegex)
-
     // Assert valid and not empty
     assertFalse(simpleMatch.isEmpty())
     assertFalse(simpleMatchCS.isEmpty())
@@ -430,7 +422,6 @@ class ExpressionMatchTest {
       ExpressionMatch.MatchMode.MatchWildcard,
       caseSensitive = false
     )
-    println(mask1.positiveRegex)
     assertTrue(mask1.match("coolguy!ab@127.0.0.1"))
     assertTrue(mask1.match("cooldud3!~bc@127.0.0.1"))
     assertFalse(mask1.match("coolguy!ab@127.0.0.5"))
@@ -441,7 +432,6 @@ class ExpressionMatchTest {
       ExpressionMatch.MatchMode.MatchWildcard,
       caseSensitive = false
     )
-    println(mask2.positiveRegex)
     assertTrue(mask2.match("coolguy!ab@127.0.0.1"))
     assertTrue(mask2.match("cooldud3!~bc@127.0.0.1"))
     assertTrue(mask2.match("cool132!ab@example.com"))
@@ -453,7 +443,6 @@ class ExpressionMatchTest {
       ExpressionMatch.MatchMode.MatchWildcard,
       caseSensitive = false
     )
-    println(mask3.positiveRegex)
     assertTrue(mask3.match("cool!guyab@127.0.0.1"))
     assertTrue(mask3.match("cool!~dudebc@127.0.0.1"))
     assertTrue(mask3.match("cool!312ab@example.com"))
@@ -468,7 +457,6 @@ class ExpressionMatchTest {
       ExpressionMatch.MatchMode.MatchWildcard,
       caseSensitive = false
     )
-    println(mask4.positiveRegex)
     assertTrue(mask4.match("cool[guy]!guy@127.0.0.1"))
     assertTrue(mask4.match("cool[guy]!a@example.com"))
     assertFalse(mask4.match("coolg!ab@127.0.0.1"))
-- 
GitLab