diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt
index 4cfb13990b9ffb4069d3816039aafaff4496d5e8..2a2e048a8babb9fd1e450948cd0306558a58204e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListFragment.kt
@@ -114,7 +114,7 @@ class AliasListFragment : SettingsFragment(), SettingsFragment.Savable,
 
   override fun hasChanged() = aliasManager?.let { (it, data) ->
     applyChanges(data)
-    data.aliasList() != it.aliasList()
+    data != it
   } ?: false
 
   private fun applyChanges(data: AliasManager) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
index 84f18336a6413f111e9287b5b1199f64c9779d1a..6800dcf640bf27634b76f7cdfbd5d4d4688b1c5b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
@@ -158,16 +158,7 @@ abstract class ChatListBaseFragment : SettingsFragment(), SettingsFragment.Savab
   override fun hasChanged() = chatlist?.let { (it, data) ->
     applyChanges(data, it)
 
-    it == null ||
-    data.bufferViewName() != it.bufferViewName() ||
-    data.showSearch() != it.showSearch() ||
-    data.sortAlphabetically() != it.sortAlphabetically() ||
-    data.addNewBuffersAutomatically() != it.addNewBuffersAutomatically() ||
-    data.hideInactiveBuffers() != it.hideInactiveBuffers() ||
-    data.hideInactiveNetworks() != it.hideInactiveNetworks() ||
-    data.allowedBufferTypes() != it.allowedBufferTypes() ||
-    data.networkId() != it.networkId() ||
-    data.minimumActivity() != it.minimumActivity()
+    data != it
   } ?: true
 
   protected fun applyChanges(data: BufferViewConfig, old: BufferViewConfig?) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListFragment.kt
index ebadca8a18929b13f10e7d4d5e1fef568cbbb3ee..980894bcfc92a83ffceea73be0d6c545aa8a794a 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListFragment.kt
@@ -189,9 +189,7 @@ class HighlightListFragment : SettingsFragment(), SettingsFragment.Savable,
 
   override fun hasChanged() = ruleManager?.let { (it, data) ->
     applyChanges(data)
-    data.highlightNick() != it.highlightNick() ||
-    data.nicksCaseSensitive() != it.nicksCaseSensitive() ||
-    data.highlightRuleList() != it.highlightRuleList()
+    data != it
   } ?: false
 
   private fun applyChanges(data: HighlightRuleManager) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt
index 724f719e4e81d4cf17c9e8a6e4dadc05fdc991c4..924d91d46f6945d905bdb11971b66484c0bc3e24 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityBaseFragment.kt
@@ -147,17 +147,7 @@ abstract class IdentityBaseFragment : SettingsFragment(), SettingsFragment.Savab
   override fun hasChanged() = identity?.let { (it, data) ->
     applyChanges(data)
 
-    it == null ||
-    data.identityName() != it.identityName() ||
-    data.realName() != it.realName() ||
-    data.ident() != it.ident() ||
-    data.kickReason() != it.kickReason() ||
-    data.partReason() != it.partReason() ||
-    data.quitReason() != it.quitReason() ||
-    data.awayReason() != it.awayReason() ||
-    data.detachAwayEnabled() != it.detachAwayEnabled() ||
-    data.detachAwayReason() != it.detachAwayReason() ||
-    data.nicks() != it.nicks()
+    data != it
   } ?: true
 
   protected fun applyChanges(data: Identity) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt
index b1bf65b5f02af85f3697c208a289cd39e33cd1f6..4cb2085372cb8c32eed6fd728f9673f1774399a8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListFragment.kt
@@ -105,7 +105,7 @@ class IgnoreListFragment : SettingsFragment(), SettingsFragment.Savable,
 
   override fun hasChanged() = ignoreListManager?.let { (it, data) ->
     applyChanges(data)
-    data.ignoreList() != it.ignoreList()
+    data != it
   } ?: false
 
   private fun applyChanges(data: IgnoreListManager) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt
index 0af5ac7f57290f0aebff1e4a079f257cc0750c87..86461825004ff404956804aa7a0f8070503effc0 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkBaseFragment.kt
@@ -238,26 +238,7 @@ abstract class NetworkBaseFragment : SettingsFragment(), SettingsFragment.Savabl
   override fun hasChanged() = network?.let { (it, data) ->
     applyChanges(data)
 
-    it == null ||
-    data.networkName() != it.networkName() ||
-    data.identity() != it.identity() ||
-    data.serverList() != it.serverList() ||
-    data.useSasl() != it.useSasl() ||
-    data.saslAccount() != it.saslAccount() ||
-    data.saslPassword() != it.saslPassword() ||
-    data.useAutoIdentify() != it.useAutoIdentify() ||
-    data.autoIdentifyService() != it.autoIdentifyService() ||
-    data.autoIdentifyPassword() != it.autoIdentifyPassword() ||
-    data.useAutoReconnect() != it.useAutoReconnect() ||
-    data.autoReconnectInterval() != it.autoReconnectInterval() ||
-    data.autoReconnectRetries() != it.autoReconnectRetries() ||
-    data.unlimitedReconnectRetries() != it.unlimitedReconnectRetries() ||
-    data.rejoinChannels() != it.rejoinChannels() ||
-    data.perform() != it.perform() ||
-    data.useCustomMessageRate() != it.useCustomMessageRate() ||
-    data.messageRateBurstSize() != it.messageRateBurstSize() ||
-    data.unlimitedMessageRate() != it.unlimitedMessageRate() ||
-    data.messageRateDelay() != it.messageRateDelay()
+    data != it
   } ?: true
 
   protected fun applyChanges(data: Network) {
diff --git a/gradle.properties b/gradle.properties
index cd42ec04a3cfc047e41ce86dbe94d860f93e6e24..cf36e9a16b3735239d21711a1523185b100f2df8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -11,5 +11,7 @@ org.gradle.jvmargs=-Xmx2048m
 # This option should only be used with decoupled projects. More details, visit
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 org.gradle.parallel=true
+# Disable configure on demand (Android Studio doesn’t like it)
+org.gradle.configureondemand=false
 # Enable new Android D8 Dexer
 android.enableD8=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 45a558e62333e9d88df61cf072ac2996cabb2273..91309ff2c89af4723d0a89a36a1f481f877ff63a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https://services.gradle.org/distributions/gradle-4.5-all.zip
+distributionUrl=https://services.gradle.org/distributions/gradle-4.7-all.zip
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
index fadb2eb3704f418a24dc98a9ae75e01c78a0b281..208df0371aca5b0e8396b9b85319bba6c0e846a5 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
@@ -63,7 +63,28 @@ class Message(
     }
   }
 
+
   override fun toString(): String {
     return "Message(messageId=$messageId, time=$time, type=$type, flag=$flag, bufferInfo=$bufferInfo, sender='$sender', senderPrefixes='$senderPrefixes', content='$content')"
   }
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as Message
+
+    if (messageId != other.messageId) return false
+    if (time != other.time) return false
+    if (type != other.type) return false
+    if (flag != other.flag) return false
+    if (bufferInfo != other.bufferInfo) return false
+    if (sender != other.sender) return false
+    if (senderPrefixes != other.senderPrefixes) return false
+    if (realName != other.realName) return false
+    if (avatarUrl != other.avatarUrl) return false
+    if (content != other.content) return false
+
+    return true
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
index ebe0b3ff9afe3a123683188d927788f113b07e8b..981d2b6b40610b36559d5a3fbe26de205486c4fb 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializer.kt
@@ -36,7 +36,7 @@ object MessageSerializer : Serializer<Message> {
         Instant.ofEpochSecond(IntSerializer.deserialize(buffer, features).toLong()),
       type = Message.MessageType.of(IntSerializer.deserialize(buffer, features)),
       flag = Message.MessageFlag.of(
-        ByteSerializer.deserialize(buffer, features).toInt()
+        ByteSerializer.deserialize(buffer, features).toInt() and 0xff
       ),
       bufferInfo = BufferInfoSerializer.deserialize(buffer, features),
       sender = StringSerializer.UTF8.deserialize(buffer, features) ?: "",
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
index c618c7a74c70b310031916f912bcda31b80975c1..67922af8a49a681904911e4c2f0ddab4429c2c39 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
@@ -170,4 +170,23 @@ class AliasManager constructor(
   }
 
   private var _aliases = listOf<IAliasManager.Alias>()
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as AliasManager
+
+    if (_aliases != other._aliases) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    return _aliases.hashCode()
+  }
+
+  override fun toString(): String {
+    return "AliasManager(_aliases=$_aliases)"
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
index deb0381b6740af46dfab73e9ca7213ff7e2dc5c5..08cd143c429e0975728eda6bc0a6790aaf6c4481 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
@@ -241,6 +241,7 @@ class BufferViewConfig constructor(
     super.setSortAlphabetically(sortAlphabetically)
   }
 
+
   private val _bufferViewId: Int = bufferViewId
   private var _bufferViewName: String = ""
     set(value) {
@@ -326,4 +327,44 @@ class BufferViewConfig constructor(
       insertBufferSorted(info, bufferSyncer)
     }
   }
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as BufferViewConfig
+
+    if (_bufferViewId != other._bufferViewId) return false
+    if (_bufferViewName != other._bufferViewName) return false
+    if (_networkId != other._networkId) return false
+    if (_addNewBuffersAutomatically != other._addNewBuffersAutomatically) return false
+    if (_sortAlphabetically != other._sortAlphabetically) return false
+    if (_hideInactiveBuffers != other._hideInactiveBuffers) return false
+    if (_hideInactiveNetworks != other._hideInactiveNetworks) return false
+    if (_disableDecoration != other._disableDecoration) return false
+    if (_allowedBufferTypes != other._allowedBufferTypes) return false
+    if (_minimumActivity != other._minimumActivity) return false
+    if (_showSearch != other._showSearch) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = _bufferViewId
+    result = 31 * result + _bufferViewName.hashCode()
+    result = 31 * result + _networkId
+    result = 31 * result + _addNewBuffersAutomatically.hashCode()
+    result = 31 * result + _sortAlphabetically.hashCode()
+    result = 31 * result + _hideInactiveBuffers.hashCode()
+    result = 31 * result + _hideInactiveNetworks.hashCode()
+    result = 31 * result + _disableDecoration.hashCode()
+    result = 31 * result + _allowedBufferTypes.hashCode()
+    result = 31 * result + _minimumActivity.hashCode()
+    result = 31 * result + _showSearch.hashCode()
+    return result
+  }
+
+  override fun toString(): String {
+    return "BufferViewConfig(_bufferViewId=$_bufferViewId, _bufferViewName='$_bufferViewName', _networkId=$_networkId, _addNewBuffersAutomatically=$_addNewBuffersAutomatically, _sortAlphabetically=$_sortAlphabetically, _hideInactiveBuffers=$_hideInactiveBuffers, _hideInactiveNetworks=$_hideInactiveNetworks, _disableDecoration=$_disableDecoration, _allowedBufferTypes=$_allowedBufferTypes, _minimumActivity=$_minimumActivity, _showSearch=$_showSearch)"
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManager.kt
index 1814b07b30ab1a819d5c3e5d70de670e650ba8f2..b70603e8fe6e87caef67c3e59b53e79722ae12b3 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManager.kt
@@ -134,4 +134,28 @@ class HighlightRuleManager(
   private var _highlightRuleList = emptyList<HighlightRule>()
   private var _highlightNick = IHighlightRuleManager.HighlightNickType.CurrentNick
   private var _nicksCaseSensitive = false
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as HighlightRuleManager
+
+    if (_highlightRuleList != other._highlightRuleList) return false
+    if (_highlightNick != other._highlightNick) return false
+    if (_nicksCaseSensitive != other._nicksCaseSensitive) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = _highlightRuleList.hashCode()
+    result = 31 * result + _highlightNick.hashCode()
+    result = 31 * result + _nicksCaseSensitive.hashCode()
+    return result
+  }
+
+  override fun toString(): String {
+    return "HighlightRuleManager(_highlightRuleList=$_highlightRuleList, _highlightNick=$_highlightNick, _nicksCaseSensitive=$_nicksCaseSensitive)"
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Identity.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Identity.kt
index 2c673f0efc3a368c48f616519db7735706684413..bd4cb588d58861230a406b474d320fdaef472aeb 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Identity.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Identity.kt
@@ -286,4 +286,60 @@ class Identity constructor(
       field = value
       _change.onNext(Unit)
     }
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as Identity
+
+    if (_identityId != other._identityId) return false
+    if (_identityName != other._identityName) return false
+    if (_realName != other._realName) return false
+    if (_nicks != other._nicks) return false
+    if (_awayNick != other._awayNick) return false
+    if (_awayNickEnabled != other._awayNickEnabled) return false
+    if (_awayReason != other._awayReason) return false
+    if (_awayReasonEnabled != other._awayReasonEnabled) return false
+    if (_autoAwayEnabled != other._autoAwayEnabled) return false
+    if (_autoAwayTime != other._autoAwayTime) return false
+    if (_autoAwayReason != other._autoAwayReason) return false
+    if (_autoAwayReasonEnabled != other._autoAwayReasonEnabled) return false
+    if (_detachAwayEnabled != other._detachAwayEnabled) return false
+    if (_detachAwayReason != other._detachAwayReason) return false
+    if (_detachAwayReasonEnabled != other._detachAwayReasonEnabled) return false
+    if (_ident != other._ident) return false
+    if (_kickReason != other._kickReason) return false
+    if (_partReason != other._partReason) return false
+    if (_quitReason != other._quitReason) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = _identityId
+    result = 31 * result + (_identityName?.hashCode() ?: 0)
+    result = 31 * result + (_realName?.hashCode() ?: 0)
+    result = 31 * result + _nicks.hashCode()
+    result = 31 * result + (_awayNick?.hashCode() ?: 0)
+    result = 31 * result + _awayNickEnabled.hashCode()
+    result = 31 * result + (_awayReason?.hashCode() ?: 0)
+    result = 31 * result + _awayReasonEnabled.hashCode()
+    result = 31 * result + _autoAwayEnabled.hashCode()
+    result = 31 * result + _autoAwayTime
+    result = 31 * result + (_autoAwayReason?.hashCode() ?: 0)
+    result = 31 * result + _autoAwayReasonEnabled.hashCode()
+    result = 31 * result + _detachAwayEnabled.hashCode()
+    result = 31 * result + (_detachAwayReason?.hashCode() ?: 0)
+    result = 31 * result + _detachAwayReasonEnabled.hashCode()
+    result = 31 * result + (_ident?.hashCode() ?: 0)
+    result = 31 * result + (_kickReason?.hashCode() ?: 0)
+    result = 31 * result + (_partReason?.hashCode() ?: 0)
+    result = 31 * result + (_quitReason?.hashCode() ?: 0)
+    return result
+  }
+
+  override fun toString(): String {
+    return "Identity(_identityId=$_identityId, _identityName=$_identityName, _realName=$_realName, _nicks=$_nicks, _awayNick=$_awayNick, _awayNickEnabled=$_awayNickEnabled, _awayReason=$_awayReason, _awayReasonEnabled=$_awayReasonEnabled, _autoAwayEnabled=$_autoAwayEnabled, _autoAwayTime=$_autoAwayTime, _autoAwayReason=$_autoAwayReason, _autoAwayReasonEnabled=$_autoAwayReasonEnabled, _detachAwayEnabled=$_detachAwayEnabled, _detachAwayReason=$_detachAwayReason, _detachAwayReasonEnabled=$_detachAwayReasonEnabled, _ident=$_ident, _kickReason=$_kickReason, _partReason=$_partReason, _quitReason=$_quitReason)"
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt
index d30b9b453808b3bbadc98fb7630b22c86f7f18f9..fa580970595651a78cd5a15ae946070d956e8ed0 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt
@@ -2,15 +2,20 @@ package de.kuschku.libquassel.quassel.syncables
 
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.syncables.interfaces.IIgnoreListManager
+import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.session.Session
+import de.kuschku.libquassel.session.SignalProxy
 import de.kuschku.libquassel.util.GlobTransformer
 import de.kuschku.libquassel.util.flag.and
 import io.reactivex.subjects.BehaviorSubject
 import java.io.Serializable
 
 class IgnoreListManager constructor(
-  private val session: Session
-) : SyncableObject(session, "IgnoreListManager"), IIgnoreListManager {
+  private val session: ISession,
+  proxy: SignalProxy
+) : SyncableObject(proxy, "IgnoreListManager"), IIgnoreListManager {
+  constructor(session: Session) : this(session, session)
+
   override fun toVariantMap(): QVariantMap = mapOf(
     "IgnoreList" to QVariant.of(initIgnoreList(), Type.QVariantMap)
   )
@@ -100,7 +105,7 @@ class IgnoreListManager constructor(
 
   fun updates() = live_updates.map { this }
 
-  fun copy() = IgnoreListManager(session).also {
+  fun copy() = IgnoreListManager(session, proxy).also {
     it.fromVariantMap(toVariantMap())
   }
 
@@ -253,6 +258,27 @@ class IgnoreListManager constructor(
     set(value) {
       field = value
       live_updates.onNext(Unit)
-      if (initialized) session.backlogManager.updateIgnoreRules()
+      if (initialized) session.backlogManager?.updateIgnoreRules()
     }
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as IgnoreListManager
+
+    if (_ignoreList != other._ignoreList) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    return _ignoreList.hashCode()
+  }
+
+  override fun toString(): String {
+    return "IgnoreListManager(_ignoreList=$_ignoreList)"
+  }
+
+
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt
index 16d50a6f2b658b80f6db940a846d42fbb258f357..9dbfb0a5617363750728d52bfe94afb525c3df88 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt
@@ -707,7 +707,7 @@ class Network constructor(
     ),
     "identityId" to QVariant.of(identity(), QType.IdentityId),
     "isConnected" to QVariant.of(isConnected(), Type.Bool),
-    "connectionState" to QVariant.of(connectionState(), Type.Int),
+    "connectionState" to QVariant.of(connectionState().value, Type.Int),
     "useRandomServer" to QVariant.of(useRandomServer(), Type.Bool),
     "perform" to QVariant.of(perform(), Type.QStringList),
     "useAutoIdentify" to QVariant.of(useAutoIdentify(), Type.Bool),
@@ -1020,6 +1020,73 @@ class Network constructor(
 
   private val live_networkInfo = BehaviorSubject.createDefault(Unit)
 
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as Network
+
+    if (_networkId != other._networkId) return false
+    if (_identity != other._identity) return false
+    if (_networkName != other._networkName) return false
+    if (_serverList != other._serverList) return false
+    if (_useRandomServer != other._useRandomServer) return false
+    if (_perform != other._perform) return false
+    if (_useAutoIdentify != other._useAutoIdentify) return false
+    if (_autoIdentifyService != other._autoIdentifyService) return false
+    if (_autoIdentifyPassword != other._autoIdentifyPassword) return false
+    if (_useSasl != other._useSasl) return false
+    if (_saslAccount != other._saslAccount) return false
+    if (_saslPassword != other._saslPassword) return false
+    if (_useAutoReconnect != other._useAutoReconnect) return false
+    if (_autoReconnectInterval != other._autoReconnectInterval) return false
+    if (_autoReconnectRetries != other._autoReconnectRetries) return false
+    if (_unlimitedReconnectRetries != other._unlimitedReconnectRetries) return false
+    if (_rejoinChannels != other._rejoinChannels) return false
+    if (_useCustomMessageRate != other._useCustomMessageRate) return false
+    if (_messageRateBurstSize != other._messageRateBurstSize) return false
+    if (_messageRateDelay != other._messageRateDelay) return false
+    if (_unlimitedMessageRate != other._unlimitedMessageRate) return false
+    if (_codecForServer != other._codecForServer) return false
+    if (_codecForEncoding != other._codecForEncoding) return false
+    if (_codecForDecoding != other._codecForDecoding) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = _networkId
+    result = 31 * result + _identity
+    result = 31 * result + _networkName.hashCode()
+    result = 31 * result + _serverList.hashCode()
+    result = 31 * result + _useRandomServer.hashCode()
+    result = 31 * result + _perform.hashCode()
+    result = 31 * result + _useAutoIdentify.hashCode()
+    result = 31 * result + _autoIdentifyService.hashCode()
+    result = 31 * result + _autoIdentifyPassword.hashCode()
+    result = 31 * result + _useSasl.hashCode()
+    result = 31 * result + _saslAccount.hashCode()
+    result = 31 * result + _saslPassword.hashCode()
+    result = 31 * result + _useAutoReconnect.hashCode()
+    result = 31 * result + _autoReconnectInterval
+    result = 31 * result + _autoReconnectRetries
+    result = 31 * result + _unlimitedReconnectRetries.hashCode()
+    result = 31 * result + _rejoinChannels.hashCode()
+    result = 31 * result + _useCustomMessageRate.hashCode()
+    result = 31 * result + _messageRateBurstSize
+    result = 31 * result + _messageRateDelay
+    result = 31 * result + _unlimitedMessageRate.hashCode()
+    result = 31 * result + _codecForServer.hashCode()
+    result = 31 * result + _codecForEncoding.hashCode()
+    result = 31 * result + _codecForDecoding.hashCode()
+    return result
+  }
+
+  override fun toString(): String {
+    return "Network(_networkId=$_networkId, _identity=$_identity, _networkName='$_networkName', _serverList=$_serverList, _useRandomServer=$_useRandomServer, _perform=$_perform, _useAutoIdentify=$_useAutoIdentify, _autoIdentifyService='$_autoIdentifyService', _autoIdentifyPassword='$_autoIdentifyPassword', _useSasl=$_useSasl, _saslAccount='$_saslAccount', _saslPassword='$_saslPassword', _useAutoReconnect=$_useAutoReconnect, _autoReconnectInterval=$_autoReconnectInterval, _autoReconnectRetries=$_autoReconnectRetries, _unlimitedReconnectRetries=$_unlimitedReconnectRetries, _rejoinChannels=$_rejoinChannels, _useCustomMessageRate=$_useCustomMessageRate, _messageRateBurstSize=$_messageRateBurstSize, _messageRateDelay=$_messageRateDelay, _unlimitedMessageRate=$_unlimitedMessageRate, _codecForServer=$_codecForServer, _codecForEncoding=$_codecForEncoding, _codecForDecoding=$_codecForDecoding)"
+  }
+
   companion object {
     val NULL = Network(-1, SignalProxy.NULL)
   }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/NetworkConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/NetworkConfig.kt
index 65b5d0771300ff419ed8aac76e33d78e4da3a652..95e9a44d927006fb13036100cba5012d5f82925c 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/NetworkConfig.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/NetworkConfig.kt
@@ -104,4 +104,39 @@ class NetworkConfig constructor(
   private var _autoWhoNickLimit: Int = 200
   private var _autoWhoDelay: Int = 5
   private var _standardCtcp: Boolean = false
+
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as NetworkConfig
+
+    if (_pingTimeoutEnabled != other._pingTimeoutEnabled) return false
+    if (_pingInterval != other._pingInterval) return false
+    if (_maxPingCount != other._maxPingCount) return false
+    if (_autoWhoEnabled != other._autoWhoEnabled) return false
+    if (_autoWhoInterval != other._autoWhoInterval) return false
+    if (_autoWhoNickLimit != other._autoWhoNickLimit) return false
+    if (_autoWhoDelay != other._autoWhoDelay) return false
+    if (_standardCtcp != other._standardCtcp) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = _pingTimeoutEnabled.hashCode()
+    result = 31 * result + _pingInterval
+    result = 31 * result + _maxPingCount
+    result = 31 * result + _autoWhoEnabled.hashCode()
+    result = 31 * result + _autoWhoInterval
+    result = 31 * result + _autoWhoNickLimit
+    result = 31 * result + _autoWhoDelay
+    result = 31 * result + _standardCtcp.hashCode()
+    return result
+  }
+
+  override fun toString(): String {
+    return "NetworkConfig(_pingTimeoutEnabled=$_pingTimeoutEnabled, _pingInterval=$_pingInterval, _maxPingCount=$_maxPingCount, _autoWhoEnabled=$_autoWhoEnabled, _autoWhoInterval=$_autoWhoInterval, _autoWhoNickLimit=$_autoWhoNickLimit, _autoWhoDelay=$_autoWhoDelay, _standardCtcp=$_standardCtcp)"
+  }
 }
diff --git a/lib/src/test/java/de/kuschku/libquassel/SerializerUnitTest.kt b/lib/src/test/java/de/kuschku/libquassel/SerializerUnitTest.kt
deleted file mode 100644
index fe40b8e9e2a703f85468c1b52aa415a23639cab3..0000000000000000000000000000000000000000
--- a/lib/src/test/java/de/kuschku/libquassel/SerializerUnitTest.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-package de.kuschku.libquassel
-
-import de.kuschku.libquassel.protocol.primitive.serializer.*
-import de.kuschku.libquassel.quassel.QuasselFeatures
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
-import de.kuschku.libquassel.util.nio.ChainedByteBuffer
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.threeten.bp.Instant
-import org.threeten.bp.LocalDateTime
-import org.threeten.bp.ZoneOffset
-import java.nio.ByteBuffer
-import kotlin.experimental.inv
-
-class SerializerUnitTest {
-  @Test
-  fun boolSerializer() {
-    assertEquals(true, roundTrip(BoolSerializer, true))
-    assertEquals(false, roundTrip(BoolSerializer, false))
-  }
-
-  @Test
-  fun byteArraySerializer() {
-    val value1 = byteArrayOf()
-    assertArrayEquals(value1, roundTrip(ByteArraySerializer, ByteBuffer.wrap(value1))?.array())
-
-    val value2 = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
-    assertArrayEquals(value2, roundTrip(ByteArraySerializer, ByteBuffer.wrap(value2))?.array())
-  }
-
-  @Test
-  fun charSerializer() {
-    assertEquals(' ', roundTrip(CharSerializer, ' '))
-    assertEquals('a', roundTrip(CharSerializer, 'a'))
-    assertEquals('ä', roundTrip(CharSerializer, 'ä'))
-    assertEquals('\u0000', roundTrip(CharSerializer, '\u0000'))
-    assertEquals('\uFFFF', roundTrip(CharSerializer, '\uFFFF'))
-    assertEquals(' ', roundTrip(CharSerializer, ' '))
-    assertEquals('a', roundTrip(CharSerializer, 'a'))
-    assertEquals('ä', roundTrip(CharSerializer, 'ä'))
-  }
-
-  @Test
-  fun dateTimeSerializer() {
-    assertEquals(Instant.EPOCH, roundTrip(DateTimeSerializer, Instant.EPOCH))
-    val now = Instant.now()
-    assertEquals(now, roundTrip(DateTimeSerializer, now))
-
-    val value1 = Instant.EPOCH.atOffset(ZoneOffset.ofTotalSeconds(1234))
-    assertEquals(
-      value1.atZoneSimilarLocal(ZoneOffset.UTC).toInstant(),
-      roundTrip(DateTimeSerializer, value1)
-    )
-    val value2 = Instant.now().atOffset(ZoneOffset.ofTotalSeconds(1234))
-    assertEquals(
-      value2.atZoneSimilarLocal(ZoneOffset.UTC).toInstant(),
-      roundTrip(DateTimeSerializer, value2)
-    )
-
-    val value3 = LocalDateTime.of(1970, 1, 1, 0, 0)
-      .atZone(ZoneOffset.systemDefault()).toInstant()
-    assertEquals(value3, roundTrip(DateTimeSerializer, value3))
-    val value4 = LocalDateTime.now().atZone(ZoneOffset.systemDefault()).toInstant()
-    assertEquals(value4, roundTrip(DateTimeSerializer, value4))
-  }
-
-  @Test
-  fun byteSerializer() {
-    assertEquals(0.toByte(), roundTrip(ByteSerializer, 0.toByte()))
-    assertEquals(Byte.MAX_VALUE, roundTrip(ByteSerializer, Byte.MAX_VALUE))
-    assertEquals(Byte.MIN_VALUE, roundTrip(ByteSerializer, Byte.MIN_VALUE))
-    assertEquals((0.toByte().inv()), roundTrip(ByteSerializer, (0.toByte().inv())))
-  }
-
-  @Test
-  fun shortSerializer() {
-    assertEquals(0.toShort(), roundTrip(ShortSerializer, 0.toShort()))
-    assertEquals(Short.MAX_VALUE, roundTrip(ShortSerializer, Short.MAX_VALUE))
-    assertEquals(Short.MIN_VALUE, roundTrip(ShortSerializer, Short.MIN_VALUE))
-    assertEquals((0.toShort().inv()), roundTrip(ShortSerializer, (0.toShort().inv())))
-  }
-
-  @Test
-  fun intSerializer() {
-    assertEquals(0, roundTrip(IntSerializer, 0))
-    assertEquals(Integer.MAX_VALUE, roundTrip(IntSerializer, Integer.MAX_VALUE))
-    assertEquals(Integer.MIN_VALUE, roundTrip(IntSerializer, Integer.MIN_VALUE))
-    assertEquals(0.inv(), roundTrip(IntSerializer, 0.inv()))
-  }
-
-  @Test
-  fun longSerializer() {
-    assertEquals(0, roundTrip(LongSerializer, 0))
-    assertEquals(Long.MAX_VALUE, roundTrip(LongSerializer, Long.MAX_VALUE))
-    assertEquals(Long.MIN_VALUE, roundTrip(LongSerializer, Long.MIN_VALUE))
-    assertEquals(0L.inv(), roundTrip(LongSerializer, 0L.inv()))
-  }
-
-  @Test
-  fun stringSerializer() {
-    assertEquals("Test", roundTrip(StringSerializer.UTF16, "Test"))
-    assertEquals("Test", roundTrip(StringSerializer.UTF8, "Test"))
-    assertEquals("Test", roundTrip(StringSerializer.C, "Test"))
-  }
-
-  @Test
-  fun networkInfoSerializer() {
-    val info = INetwork.NetworkInfo(
-      networkName = "QuakeNet",
-      identity = 5,
-      serverList = listOf(
-        INetwork.Server(
-          host = "irc.quakenet.org",
-          port = 6667
-        )
-      )
-    )
-    val info2 = info.copy()
-    info2.fromVariantMap(roundTrip(VariantMapSerializer, info.toVariantMap()))
-    assertEquals(info, info2)
-  }
-
-  companion object {
-    fun <T> roundTrip(serializer: Serializer<T>, value: T,
-                      features: QuasselFeatures = QuasselFeatures.all()): T {
-      val chainedBuffer = ChainedByteBuffer(
-        direct = false
-      )
-      serializer.serialize(chainedBuffer, value, features)
-      val buffer = chainedBuffer.toBuffer()
-      return serializer.deserialize(buffer, features)
-    }
-  }
-}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4c5aef1f0c566186efe250498502026f060e9c2d
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BoolSerializerTest.kt
@@ -0,0 +1,13 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class BoolSerializerTest {
+  @Test
+  fun testFalse() {
+    assertEquals(true, roundTrip(BoolSerializer, true))
+    assertEquals(false, roundTrip(BoolSerializer, false))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bf4e1ac036657719d1f650ccbf0cc579eef5fa61
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/BufferInfoSerializerTest.kt
@@ -0,0 +1,33 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class BufferInfoSerializerTest {
+  @Test
+  fun testBaseCase() {
+    val value = BufferInfo(
+      -1,
+      -1,
+      Buffer_Type.of(),
+      -1,
+      ""
+    )
+    Assert.assertEquals(value, roundTrip(BufferInfoSerializer, value))
+  }
+
+  @Test
+  fun testNormal() {
+    val value = BufferInfo(
+      Int.MAX_VALUE,
+      Int.MAX_VALUE,
+      Buffer_Type.of(*Buffer_Type.validValues),
+      Int.MAX_VALUE,
+      "äẞ\u0000\uFFFF"
+    )
+    Assert.assertEquals(value, roundTrip(BufferInfoSerializer, value))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1f7ae81c64b7f4fa63fba6a1aeb6d4f64d9e992e
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteArraySerializerTest.kt
@@ -0,0 +1,20 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertArrayEquals
+import org.junit.Test
+import java.nio.ByteBuffer
+
+class ByteArraySerializerTest {
+  @Test
+  fun testBaseCase() {
+    val value = byteArrayOf()
+    assertArrayEquals(value, roundTrip(ByteArraySerializer, ByteBuffer.wrap(value))?.array())
+  }
+
+  @Test
+  fun testNormal() {
+    val value = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
+    assertArrayEquals(value, roundTrip(ByteArraySerializer, ByteBuffer.wrap(value))?.array())
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..18c2e81bfbcf0af73e4116ef9e17a36039b006be
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ByteSerializerTest.kt
@@ -0,0 +1,28 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import kotlin.experimental.inv
+
+class ByteSerializerTest {
+  @Test
+  fun testZero() {
+    assertEquals(0.toByte(), roundTrip(ByteSerializer, 0.toByte()))
+  }
+
+  @Test
+  fun testMinimal() {
+    assertEquals(Byte.MIN_VALUE, roundTrip(ByteSerializer, Byte.MIN_VALUE))
+  }
+
+  @Test
+  fun testMaximal() {
+    assertEquals(Byte.MAX_VALUE, roundTrip(ByteSerializer, Byte.MAX_VALUE))
+  }
+
+  @Test
+  fun testAllOnes() {
+    assertEquals((0.toByte().inv()), roundTrip(ByteSerializer, (0.toByte().inv())))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..75dc87678ba316c6db18d5ec24cac334e8d66450
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/CharSerializerTest.kt
@@ -0,0 +1,16 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class CharSerializerTest {
+  @Test
+  fun testAll() {
+    assertEquals(' ', roundTrip(CharSerializer, ' '))
+    assertEquals('a', roundTrip(CharSerializer, 'a'))
+    assertEquals('ä', roundTrip(CharSerializer, 'ä'))
+    assertEquals('\u0000', roundTrip(CharSerializer, '\u0000'))
+    assertEquals('\uFFFF', roundTrip(CharSerializer, '\uFFFF'))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b614f3f3ed114c499f807046d0967ebeb5a7fc63
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializerTest.kt
@@ -0,0 +1,38 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.threeten.bp.Instant
+import org.threeten.bp.LocalDateTime
+import org.threeten.bp.ZoneOffset
+
+class DateTimeSerializerTest {
+  @Test
+  fun testEpoch() {
+    val value = roundTrip(DateTimeSerializer, Instant.EPOCH)
+    assertEquals(Instant.EPOCH, value)
+  }
+
+  @Test
+  fun testEpochAtTimezone() {
+    val value = Instant.EPOCH.atOffset(ZoneOffset.ofTotalSeconds(1234))
+    assertEquals(
+      value.atZoneSimilarLocal(ZoneOffset.UTC).toInstant(),
+      roundTrip(DateTimeSerializer, value)
+    )
+  }
+
+  @Test
+  fun testEpochByCalendarAtTimezone() {
+    val value = LocalDateTime.of(1970, 1, 1, 0, 0)
+      .atZone(ZoneOffset.systemDefault()).toInstant()
+    assertEquals(value, roundTrip(DateTimeSerializer, value))
+  }
+
+  @Test
+  fun testNormalCase() {
+    val value = LocalDateTime.now().atZone(ZoneOffset.systemDefault()).toInstant()
+    assertEquals(value, roundTrip(DateTimeSerializer, value))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ca270af21622d3cadd88921c532c96062cae16c8
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/IntSerializerTest.kt
@@ -0,0 +1,27 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class IntSerializerTest {
+  @Test
+  fun testZero() {
+    assertEquals(0, roundTrip(IntSerializer, 0))
+  }
+
+  @Test
+  fun testMinimal() {
+    assertEquals(Int.MIN_VALUE, roundTrip(IntSerializer, Int.MIN_VALUE))
+  }
+
+  @Test
+  fun testMaximal() {
+    assertEquals(Int.MAX_VALUE, roundTrip(IntSerializer, Int.MAX_VALUE))
+  }
+
+  @Test
+  fun testAllOnes() {
+    assertEquals(0.inv(), roundTrip(IntSerializer, 0.inv()))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..43d8d0387b627afe2e92994352061925e182cfdd
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/LongSerializerTest.kt
@@ -0,0 +1,27 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class LongSerializerTest {
+  @Test
+  fun testZero() {
+    assertEquals(0L, roundTrip(LongSerializer, 0L))
+  }
+
+  @Test
+  fun testMinimal() {
+    assertEquals(Long.MIN_VALUE, roundTrip(LongSerializer, Long.MIN_VALUE))
+  }
+
+  @Test
+  fun testMaximal() {
+    assertEquals(Long.MAX_VALUE, roundTrip(LongSerializer, Long.MAX_VALUE))
+  }
+
+  @Test
+  fun testAllOnes() {
+    assertEquals(0L.inv(), roundTrip(LongSerializer, 0L.inv()))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..368503201d02edd7c1cd11538ffb9db79e7b73e4
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/MessageSerializerTest.kt
@@ -0,0 +1,134 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.protocol.Message
+import de.kuschku.libquassel.protocol.Message_Flag
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.QuasselFeatures
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.threeten.bp.Instant
+
+class MessageSerializerTest {
+  @Test
+  fun testBaseCaseNoFeatures() {
+    val value = Message(
+      -1,
+      Instant.EPOCH,
+      Message_Type.of(),
+      Message_Flag.of(),
+      BufferInfo(
+        -1,
+        -1,
+        Buffer_Type.of(),
+        -1,
+        ""
+      ),
+      "",
+      "",
+      "",
+      "",
+      ""
+    )
+    val other = roundTrip(MessageSerializer, value, features = QuasselFeatures.empty())
+    assertEquals(value, other)
+  }
+
+  @Test
+  fun testNormalNoFeatures() {
+    val value = Message(
+      Int.MAX_VALUE,
+      Instant.ofEpochMilli(1524601750000),
+      Message_Type.of(*Message_Type.values()),
+      Message_Flag.of(*Message_Flag.values()),
+      BufferInfo(
+        Int.MAX_VALUE,
+        Int.MAX_VALUE,
+        Buffer_Type.of(*Buffer_Type.validValues),
+        Int.MAX_VALUE,
+        "äẞ\u0000\uFFFF"
+      ),
+      "äẞ\u0000\uFFFF",
+      "",
+      "",
+      "",
+      "äẞ\u0000\uFFFF"
+    )
+    val other = roundTrip(MessageSerializer, value, features = QuasselFeatures.empty())
+    assertEquals(value, other)
+  }
+
+  @Test
+  fun testBaseCaseAllFeatures() {
+    val value = Message(
+      -1,
+      Instant.EPOCH,
+      Message_Type.of(),
+      Message_Flag.of(),
+      BufferInfo(
+        -1,
+        -1,
+        Buffer_Type.of(),
+        -1,
+        ""
+      ),
+      "",
+      "",
+      "",
+      "",
+      ""
+    )
+    val other = roundTrip(MessageSerializer, value, features = QuasselFeatures.all())
+    assertEquals(value, other)
+  }
+
+  @Test
+  fun testNormalAllFeatures() {
+    val value = Message(
+      Int.MAX_VALUE,
+      Instant.ofEpochMilli(1524601750000),
+      Message_Type.of(*Message_Type.values()),
+      Message_Flag.of(*Message_Flag.values()),
+      BufferInfo(
+        Int.MAX_VALUE,
+        Int.MAX_VALUE,
+        Buffer_Type.of(*Buffer_Type.validValues),
+        Int.MAX_VALUE,
+        "äẞ\u0000\uFFFF"
+      ),
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF"
+    )
+    val other = roundTrip(MessageSerializer, value, features = QuasselFeatures.all())
+    assertEquals(value, other)
+  }
+
+  @Test
+  fun testExtremeAllFeatures() {
+    val value = Message(
+      Int.MAX_VALUE,
+      Instant.ofEpochMilli(Int.MAX_VALUE * 10000L),
+      Message_Type.of(*Message_Type.values()),
+      Message_Flag.of(*Message_Flag.values()),
+      BufferInfo(
+        Int.MAX_VALUE,
+        Int.MAX_VALUE,
+        Buffer_Type.of(*Buffer_Type.validValues),
+        Int.MAX_VALUE,
+        "äẞ\u0000\uFFFF"
+      ),
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF",
+      "äẞ\u0000\uFFFF"
+    )
+    val other = roundTrip(MessageSerializer, value, features = QuasselFeatures.all())
+    assertEquals(value, other)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..107e9b30262a0986da63386a947cee3a8132a931
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ShortSerializerTest.kt
@@ -0,0 +1,28 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import kotlin.experimental.inv
+
+class ShortSerializerTest {
+  @Test
+  fun testZero() {
+    assertEquals(0.toShort(), roundTrip(ShortSerializer, 0.toShort()))
+  }
+
+  @Test
+  fun testMinimal() {
+    assertEquals(Short.MIN_VALUE, roundTrip(ShortSerializer, Short.MIN_VALUE))
+  }
+
+  @Test
+  fun testMaximal() {
+    assertEquals(Short.MAX_VALUE, roundTrip(ShortSerializer, Short.MAX_VALUE))
+  }
+
+  @Test
+  fun testAllOnes() {
+    assertEquals((0.toShort().inv()), roundTrip(ShortSerializer, (0.toShort().inv())))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..895c93072526eb325e0f5743babf3fe200ef7fc9
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializerTest.kt
@@ -0,0 +1,14 @@
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class StringSerializerTest {
+  @Test
+  fun testAll() {
+    assertEquals("Test", roundTrip(StringSerializer.UTF16, "Test"))
+    assertEquals("Test", roundTrip(StringSerializer.UTF8, "Test"))
+    assertEquals("Test", roundTrip(StringSerializer.C, "Test"))
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d6f16324c8ed4f13aabc41c9cda9515737fb86d6
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt
@@ -0,0 +1,29 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class AliasManagerTest {
+  @Test
+  fun testSerialization() {
+    val original = AliasManager(SignalProxy.NULL)
+    original.setAliasList(original.defaults())
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = AliasManager(SignalProxy.NULL)
+    original.setAliasList(original.defaults())
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfigTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfigTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..920d3a6928fa9e5b2a58f4831a5805e80e6d67d4
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfigTest.kt
@@ -0,0 +1,49 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.Buffer_Activity
+import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.*
+import org.junit.Assert
+import org.junit.Test
+
+class BufferViewConfigTest {
+  @Test
+  fun testSerialization() {
+    val original = BufferViewConfig(randomUInt(), SignalProxy.NULL)
+    original.setBufferViewName(randomString())
+    original.setNetworkId(randomUInt())
+    original.setAddNewBuffersAutomatically(randomBoolean())
+    original.setSortAlphabetically(randomBoolean())
+    original.setHideInactiveNetworks(randomBoolean())
+    original.setHideInactiveNetworks(randomBoolean())
+    original.setDisableDecoration(randomBoolean())
+    original.setAllowedBufferTypes(Buffer_Type.of(*Buffer_Type.validValues))
+    original.setMinimumActivity(randomOf(*Buffer_Activity.values()).toInt())
+    original.setShowSearch(randomBoolean())
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = BufferViewConfig(randomUInt(), SignalProxy.NULL)
+    original.setBufferViewName(randomString())
+    original.setNetworkId(randomUInt())
+    original.setAddNewBuffersAutomatically(randomBoolean())
+    original.setSortAlphabetically(randomBoolean())
+    original.setHideInactiveNetworks(randomBoolean())
+    original.setHideInactiveNetworks(randomBoolean())
+    original.setDisableDecoration(randomBoolean())
+    original.setAllowedBufferTypes(Buffer_Type.of(*Buffer_Type.validValues))
+    original.setMinimumActivity(randomOf(*Buffer_Activity.values()).toInt())
+    original.setShowSearch(randomBoolean())
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..12bdead2da4634c16b606bb5845062faaa849f63
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/HighlightRuleManagerTest.kt
@@ -0,0 +1,93 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.quassel.syncables.interfaces.IHighlightRuleManager
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.randomBoolean
+import de.kuschku.libquassel.util.randomOf
+import de.kuschku.libquassel.util.randomString
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class HighlightRuleManagerTest {
+  @Test
+  fun testSerialization() {
+    val original = HighlightRuleManager(SignalProxy.NULL)
+    original.setHighlightNick(randomOf(*IHighlightRuleManager.HighlightNickType.values()).value)
+    original.setNicksCaseSensitive(randomBoolean())
+    original.setHighlightRuleList(listOf(
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      ),
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      ),
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      )
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = HighlightRuleManager(SignalProxy.NULL)
+    original.setHighlightNick(randomOf(*IHighlightRuleManager.HighlightNickType.values()).value)
+    original.setNicksCaseSensitive(randomBoolean())
+    original.setHighlightRuleList(listOf(
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      ),
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      ),
+      HighlightRuleManager.HighlightRule(
+        randomString(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomBoolean(),
+        randomString(),
+        randomString()
+      )
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IdentityTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IdentityTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..808c04b696cc6251f339b88da524925d619c3cc4
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IdentityTest.kt
@@ -0,0 +1,45 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.randomString
+import de.kuschku.libquassel.util.randomUInt
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class IdentityTest {
+  @Test
+  fun testSerialization() {
+    val original = Identity(SignalProxy.NULL)
+    original.setId(randomUInt())
+    original.setIdentityName(randomString())
+    original.setRealName(randomString())
+    original.setNicks(listOf(
+      randomString(),
+      randomString(),
+      randomString()
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = Identity(SignalProxy.NULL)
+    original.setId(randomUInt())
+    original.setIdentityName(randomString())
+    original.setRealName(randomString())
+    original.setNicks(listOf(
+      randomString(),
+      randomString(),
+      randomString()
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b48984b661079b2c1c399d60d86796a1dc109bae
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManagerTest.kt
@@ -0,0 +1,75 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.ISession
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.randomBoolean
+import de.kuschku.libquassel.util.randomOf
+import de.kuschku.libquassel.util.randomString
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class IgnoreListManagerTest {
+  @Test
+  fun testSerialization() {
+    val original = IgnoreListManager(ISession.NULL, SignalProxy.NULL)
+    original.setIgnoreList(listOf(
+      IgnoreListManager.IgnoreListItem(
+        type = randomOf(*IgnoreListManager.IgnoreType.values()),
+        ignoreRule = randomString(),
+        isRegEx = randomBoolean(),
+        strictness = randomOf(IgnoreListManager.StrictnessType.SoftStrictness,
+                              IgnoreListManager.StrictnessType.HardStrictness),
+        scope = randomOf(*IgnoreListManager.ScopeType.values()),
+        scopeRule = randomString(),
+        isActive = randomBoolean()
+      ),
+      IgnoreListManager.IgnoreListItem(
+        type = randomOf(*IgnoreListManager.IgnoreType.values()),
+        ignoreRule = randomString(),
+        isRegEx = randomBoolean(),
+        strictness = randomOf(IgnoreListManager.StrictnessType.SoftStrictness,
+                              IgnoreListManager.StrictnessType.HardStrictness),
+        scope = randomOf(*IgnoreListManager.ScopeType.values()),
+        scopeRule = randomString(),
+        isActive = randomBoolean()
+      )
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = IgnoreListManager(ISession.NULL, SignalProxy.NULL)
+    original.setIgnoreList(listOf(
+      IgnoreListManager.IgnoreListItem(
+        type = randomOf(*IgnoreListManager.IgnoreType.values()),
+        ignoreRule = randomString(),
+        isRegEx = randomBoolean(),
+        strictness = randomOf(IgnoreListManager.StrictnessType.SoftStrictness,
+                              IgnoreListManager.StrictnessType.HardStrictness),
+        scope = randomOf(*IgnoreListManager.ScopeType.values()),
+        scopeRule = randomString(),
+        isActive = randomBoolean()
+      ),
+      IgnoreListManager.IgnoreListItem(
+        type = randomOf(*IgnoreListManager.IgnoreType.values()),
+        ignoreRule = randomString(),
+        isRegEx = randomBoolean(),
+        strictness = randomOf(IgnoreListManager.StrictnessType.SoftStrictness,
+                              IgnoreListManager.StrictnessType.HardStrictness),
+        scope = randomOf(*IgnoreListManager.ScopeType.values()),
+        scopeRule = randomString(),
+        isActive = randomBoolean()
+      )
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkConfigTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkConfigTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6ce3524836f41c5c456c57898a99b4eae01e28dc
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkConfigTest.kt
@@ -0,0 +1,45 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.randomBoolean
+import de.kuschku.libquassel.util.randomUInt
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert
+import org.junit.Test
+
+class NetworkConfigTest {
+  @Test
+  fun testSerialization() {
+    val original = NetworkConfig(SignalProxy.NULL)
+    original.setPingTimeoutEnabled(randomBoolean())
+    original.setPingInterval(randomUInt())
+    original.setMaxPingCount(randomUInt())
+    original.setAutoWhoEnabled(randomBoolean())
+    original.setAutoWhoInterval(randomUInt())
+    original.setAutoWhoNickLimit(randomUInt())
+    original.setAutoWhoDelay(randomUInt())
+    original.setStandardCtcp(randomBoolean())
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = NetworkConfig(SignalProxy.NULL)
+    original.setPingTimeoutEnabled(randomBoolean())
+    original.setPingInterval(randomUInt())
+    original.setMaxPingCount(randomUInt())
+    original.setAutoWhoEnabled(randomBoolean())
+    original.setAutoWhoInterval(randomUInt())
+    original.setAutoWhoNickLimit(randomUInt())
+    original.setAutoWhoDelay(randomUInt())
+    original.setStandardCtcp(randomBoolean())
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..83c5361a70826992b8096cc1b867c5791823a3bd
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/NetworkTest.kt
@@ -0,0 +1,113 @@
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.*
+import org.junit.Assert
+import org.junit.Test
+
+class NetworkTest {
+  @Test
+  fun testSerialization() {
+    val original = Network(randomUInt(), SignalProxy.NULL)
+    original.setNetworkName(randomString())
+    original.setIdentity(randomUInt())
+    original.setActualServerList(listOf(
+      INetwork.Server(
+        host = randomString(),
+        port = randomUInt(),
+        password = randomString(),
+        useSsl = randomBoolean(),
+        sslVerify = randomBoolean(),
+        sslVersion = randomInt(),
+        useProxy = randomBoolean(),
+        proxyType = randomOf(*INetwork.ProxyType.values()).value,
+        proxyHost = randomString(),
+        proxyPort = randomUInt(),
+        proxyUser = randomString(),
+        proxyPass = randomString()
+      )
+    ))
+    original.setUseRandomServer(randomBoolean())
+    original.setPerform(listOf(
+      randomString(),
+      randomString(),
+      randomString()
+    ))
+    original.setUseAutoIdentify(randomBoolean())
+    original.setAutoIdentifyService(randomString())
+    original.setAutoIdentifyPassword(randomString())
+    original.setUseSasl(randomBoolean())
+    original.setSaslAccount(randomString())
+    original.setSaslPassword(randomString())
+    original.setUseAutoReconnect(randomBoolean())
+    original.setAutoReconnectInterval(randomUInt())
+    original.setAutoReconnectRetries(randomUShort())
+    original.setUnlimitedReconnectRetries(randomBoolean())
+    original.setRejoinChannels(randomBoolean())
+    original.setUseCustomMessageRate(randomBoolean())
+    original.setMessageRateBurstSize(randomUInt())
+    original.setMessageRateDelay(randomUInt())
+    original.setUnlimitedMessageRate(randomBoolean())
+    original.setCodecForServer(randomCharset())
+    original.setCodecForEncoding(randomCharset())
+    original.setCodecForDecoding(randomCharset())
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    Assert.assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = Network(randomUInt(), SignalProxy.NULL)
+    original.setNetworkName(randomString())
+    original.setIdentity(randomUInt())
+    original.setActualServerList(listOf(
+      INetwork.Server(
+        host = randomString(),
+        port = randomUInt(),
+        password = randomString(),
+        useSsl = randomBoolean(),
+        sslVerify = randomBoolean(),
+        sslVersion = randomInt(),
+        useProxy = randomBoolean(),
+        proxyType = randomOf(*INetwork.ProxyType.values()).value,
+        proxyHost = randomString(),
+        proxyPort = randomUInt(),
+        proxyUser = randomString(),
+        proxyPass = randomString()
+      )
+    ))
+    original.setUseRandomServer(randomBoolean())
+    original.setPerform(listOf(
+      randomString(),
+      randomString(),
+      randomString()
+    ))
+    original.setUseAutoIdentify(randomBoolean())
+    original.setAutoIdentifyService(randomString())
+    original.setAutoIdentifyPassword(randomString())
+    original.setUseSasl(randomBoolean())
+    original.setSaslAccount(randomString())
+    original.setSaslPassword(randomString())
+    original.setUseAutoReconnect(randomBoolean())
+    original.setAutoReconnectInterval(randomUInt())
+    original.setAutoReconnectRetries(randomUShort())
+    original.setUnlimitedReconnectRetries(randomBoolean())
+    original.setRejoinChannels(randomBoolean())
+    original.setUseCustomMessageRate(randomBoolean())
+    original.setMessageRateBurstSize(randomUInt())
+    original.setMessageRateDelay(randomUInt())
+    original.setUnlimitedMessageRate(randomBoolean())
+    original.setCodecForServer(randomCharset())
+    original.setCodecForEncoding(randomCharset())
+    original.setCodecForDecoding(randomCharset())
+    original.setAutoAwayActive(randomBoolean())
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    Assert.assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkInfoTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkInfoTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c77c4e8099f75f3b58c2db543352a54a229c1205
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkInfoTest.kt
@@ -0,0 +1,42 @@
+package de.kuschku.libquassel.quassel.syncables.interfaces
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class INetworkInfoTest {
+  @Test
+  fun testSerialization() {
+    val original = INetwork.NetworkInfo(
+      networkName = "QuakeNet",
+      identity = 5,
+      serverList = listOf(
+        INetwork.Server(
+          host = "irc.quakenet.org",
+          port = 6667
+        )
+      )
+    )
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    assertEquals(original, copy)
+  }
+
+  @Test
+  fun testCopy() {
+    val original = INetwork.NetworkInfo(
+      networkName = "QuakeNet",
+      identity = 5,
+      serverList = listOf(
+        INetwork.Server(
+          host = "irc.quakenet.org",
+          port = 6667
+        )
+      )
+    )
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    assertEquals(original, copy)
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/util/RandomHelpers.kt b/lib/src/test/java/de/kuschku/libquassel/util/RandomHelpers.kt
new file mode 100644
index 0000000000000000000000000000000000000000..74b01e55b178c11446301c030e5af828d9d2961b
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/util/RandomHelpers.kt
@@ -0,0 +1,28 @@
+package de.kuschku.libquassel.util
+
+import de.kuschku.libquassel.protocol.UByte
+import de.kuschku.libquassel.protocol.UInt
+import de.kuschku.libquassel.protocol.UShort
+import java.nio.charset.Charset
+import java.util.*
+
+val random = Random()
+
+fun Any?.randomBoolean(): Boolean = random.nextBoolean()
+
+fun Any?.randomByte(): Byte = random.nextInt(2 shl 8).toByte()
+fun Any?.randomUByte(): UByte = random.nextInt(Byte.MAX_VALUE.toInt()).toByte()
+
+fun Any?.randomShort(): Short = random.nextInt(2 shl 16).toShort()
+fun Any?.randomUShort(): UShort = random.nextInt(Short.MAX_VALUE.toInt()).toShort()
+
+fun Any?.randomInt(): Int = random.nextInt()
+fun Any?.randomUInt(): UInt = random.nextInt(Int.MAX_VALUE)
+
+fun Any?.randomLong(): Long = random.nextLong()
+
+fun Any?.randomString(): String = UUID.randomUUID().toString()
+
+fun <T> Any?.randomOf(vararg elements: T): T = elements[random.nextInt(elements.size)]
+
+fun Any?.randomCharset(): Charset = randomOf(*Charset.availableCharsets().values.toTypedArray())
diff --git a/lib/src/test/java/de/kuschku/libquassel/util/SerializerHelpers.kt b/lib/src/test/java/de/kuschku/libquassel/util/SerializerHelpers.kt
new file mode 100644
index 0000000000000000000000000000000000000000..be322564a6c4bb9f8a4fd9cb44971ffb0e2fe837
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/util/SerializerHelpers.kt
@@ -0,0 +1,15 @@
+package de.kuschku.libquassel.util
+
+import de.kuschku.libquassel.protocol.primitive.serializer.Serializer
+import de.kuschku.libquassel.quassel.QuasselFeatures
+import de.kuschku.libquassel.util.nio.ChainedByteBuffer
+
+fun <T> roundTrip(serializer: Serializer<T>, value: T,
+                  features: QuasselFeatures = QuasselFeatures.all()): T {
+  val chainedBuffer = ChainedByteBuffer(
+    direct = false
+  )
+  serializer.serialize(chainedBuffer, value, features)
+  val buffer = chainedBuffer.toBuffer()
+  return serializer.deserialize(buffer, features)
+}
diff --git a/malheur/build.gradle.kts b/malheur/build.gradle.kts
index 3cc2ebb1d184700cda7e6d1ca89f07ea5e062b57..1c911848724a5027a2ef3f28b477ff6e538b32bd 100644
--- a/malheur/build.gradle.kts
+++ b/malheur/build.gradle.kts
@@ -13,6 +13,11 @@ android {
     targetSdkVersion(27)
 
     consumerProguardFiles("proguard-rules.pro")
+
+    // Disable test runner analytics
+    testInstrumentationRunnerArguments = mapOf(
+      "disableAnalytics" to "true"
+    )
   }
 }
 
diff --git a/persistence/build.gradle.kts b/persistence/build.gradle.kts
index 825654e510c34c59903211ac0a25ba3d6f827903..dbeef25c75150460a1bd58263031ceebe9f4afb7 100644
--- a/persistence/build.gradle.kts
+++ b/persistence/build.gradle.kts
@@ -19,6 +19,11 @@ android {
         arguments = mapOf("room.schemaLocation" to "$projectDir/schemas")
       }
     }
+
+    // Disable test runner analytics
+    testInstrumentationRunnerArguments = mapOf(
+      "disableAnalytics" to "true"
+    )
   }
 }
 
diff --git a/slidingpanel/build.gradle.kts b/slidingpanel/build.gradle.kts
index 5ae8da0ffae08ce5abc03c347eb03ed96b20318f..de15f4bcdbe133042f4c35a4d588e434c41101c4 100644
--- a/slidingpanel/build.gradle.kts
+++ b/slidingpanel/build.gradle.kts
@@ -9,6 +9,11 @@ android {
   defaultConfig {
     minSdkVersion(14)
     targetSdkVersion(27)
+
+    // Disable test runner analytics
+    testInstrumentationRunnerArguments = mapOf(
+      "disableAnalytics" to "true"
+    )
   }
 }
 
diff --git a/viewmodel/build.gradle.kts b/viewmodel/build.gradle.kts
index 5392f4479506f3286c342d5323f73641927039b4..71ad1d035d2e8ca8cb2618432e3bc77725a5221a 100644
--- a/viewmodel/build.gradle.kts
+++ b/viewmodel/build.gradle.kts
@@ -13,6 +13,11 @@ android {
     targetSdkVersion(27)
 
     consumerProguardFiles("proguard-rules.pro")
+
+    // Disable test runner analytics
+    testInstrumentationRunnerArguments = mapOf(
+      "disableAnalytics" to "true"
+    )
   }
 }