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 6adef5e739c98e4107181fe042372e615517fac2..894167e254a73edf7e75d84b8ed00c1543895c2f 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
@@ -77,7 +77,7 @@ open class IrcUser(
     "lastAwayMessageTime" to qVariant(lastAwayMessageTime(), QtType.QDateTime),
     "whoisServiceReply" to qVariant(whoisServiceReply(), QtType.QString),
     "suserHost" to qVariant(suserHost(), QtType.QString),
-    "encrypted" to qVariant(encrypted(), QtType.Bool),
+    "encrypted" to qVariant(isEncrypted(), QtType.Bool),
 
     "channels" to qVariant(channels().toList(), QtType.QStringList),
     "userModes" to qVariant(userModes().joinToString(), QtType.QString)
@@ -222,7 +222,7 @@ open class IrcUser(
 
   override fun setUserModes(modes: String) {
     state.update {
-      copy(userModes = userModes.toSet())
+      copy(userModes = modes.toSet())
     }
     super.setUserModes(modes)
   }
@@ -292,7 +292,7 @@ open class IrcUser(
   fun lastAwayMessageTime() = state().lastAwayMessageTime
   fun whoisServiceReply() = state().whoisServiceReply
   fun suserHost() = state().suserHost
-  fun encrypted() = state().encrypted
+  fun isEncrypted() = state().encrypted
   fun userModes() = state().userModes
   fun channels() = state().channels
 }
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 d33c2a696611e8b0798b0dfe1f2c88dfdf536416..f659dab56a94db6f7a96d1670563433a94eadbfd 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
@@ -51,10 +51,10 @@ open class Network(
           ?: codecForServer,
         codecForEncoding = properties["codecForEncoding"].into<ByteBuffer>()
           ?.let(StringSerializerUtf8::deserializeRaw)
-          ?: codecForServer,
+          ?: codecForEncoding,
         codecForDecoding = properties["codecForDecoding"].into<ByteBuffer>()
           ?.let(StringSerializerUtf8::deserializeRaw)
-          ?: codecForServer,
+          ?: codecForDecoding,
         identity = properties["identityId"]
           .into(identity),
         connected = properties["isConnected"]
@@ -456,7 +456,7 @@ open class Network(
 
   override fun setIdentity(identityId: IdentityId) {
     state.update {
-      copy(identity = identity)
+      copy(identity = identityId)
     }
     super.setIdentity(identityId)
   }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfigTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfigTest.kt
index 4c4f265ec31125fbe75f9a013eaa47e7b8f0b0a5..00e208b03fca35ac5c73d1f8e789a7441516c353 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfigTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfigTest.kt
@@ -20,7 +20,7 @@ class BufferViewConfigTest {
   fun testEmpty() {
     val state = BufferViewConfigState(bufferViewId = 1)
     val actual = BufferViewConfig(state = state).apply {
-      fromVariantMap(emptyMap())
+      update(emptyMap())
     }.state()
 
     assertEquals(state, actual)
@@ -36,7 +36,7 @@ class BufferViewConfigTest {
         bufferViewId = expected.bufferViewId,
       )
     ).apply {
-      fromVariantMap(BufferViewConfig(state = expected).toVariantMap())
+      update(BufferViewConfig(state = expected).toVariantMap())
     }.state()
 
     assertEquals(expected, actual)
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManagerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManagerTest.kt
index ea5a9213233a27d9c129d6bb8eba16df62232c04..7f611aa5c878983839c13ac3e653b3e9a647afc9 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManagerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewManagerTest.kt
@@ -20,7 +20,7 @@ class BufferViewManagerTest {
   fun testEmpty() {
     val state = BufferViewManagerState()
     val actual = BufferViewManager(state = state).apply {
-      fromVariantMap(emptyMap())
+      update(emptyMap())
     }.state()
 
     assertEquals(state, actual)
@@ -32,7 +32,7 @@ class BufferViewManagerTest {
     val expected = random.nextBufferViewManager()
 
     val actual = BufferViewManager().apply {
-      fromVariantMap(BufferViewManager(state = expected).toVariantMap())
+      update(BufferViewManager(state = expected).toVariantMap())
     }.state()
 
     assertEquals(expected, actual)
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannelTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannelTest.kt
index 05e7790295a0b2e3d836c27a15f6d3f2ef3050e1..fb4d1e7f7b12982fa43620a2f8e3b11c183ab5d7 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannelTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannelTest.kt
@@ -13,6 +13,8 @@ import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
 import de.justjanne.libquassel.protocol.testutil.nextIrcChannel
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Nested
 import org.junit.jupiter.api.Test
 import kotlin.random.Random
 
@@ -24,7 +26,7 @@ class IrcChannelTest {
       name = "#name"
     )
     val actual = IrcChannel(state = state).apply {
-      fromVariantMap(emptyMap())
+      update(emptyMap())
     }.state()
 
     assertEquals(state, actual)
@@ -41,9 +43,43 @@ class IrcChannelTest {
         name = expected.name,
       )
     ).apply {
-      fromVariantMap(IrcChannel(state = expected).toVariantMap())
+      update(IrcChannel(state = expected).toVariantMap())
     }.state()
 
     assertEquals(expected, actual)
   }
+
+  @Nested
+  inner class Setters {
+    @Test
+    fun testTopic() {
+      val random = Random(1337)
+      val channel = IrcChannel(state = random.nextIrcChannel(NetworkId(random.nextInt())))
+
+      assertNotEquals("IMPLEMENTATION DEFINED CONTROVERSY", channel.topic())
+      channel.setTopic("IMPLEMENTATION DEFINED CONTROVERSY")
+      assertEquals("IMPLEMENTATION DEFINED CONTROVERSY", channel.topic())
+    }
+
+    @Test
+    fun testPassword() {
+      val random = Random(1337)
+      val channel = IrcChannel(state = random.nextIrcChannel(NetworkId(random.nextInt())))
+
+      assertNotEquals("hunter2", channel.password())
+      channel.setPassword("hunter2")
+      assertEquals("hunter2", channel.password())
+    }
+
+    @Test
+    fun testEncrypted() {
+      val random = Random(1337)
+      val channel = IrcChannel(state = random.nextIrcChannel(NetworkId(random.nextInt())))
+
+      channel.setEncrypted(false)
+      assertEquals(false, channel.isEncrypted())
+      channel.setEncrypted(true)
+      assertEquals(true, channel.isEncrypted())
+    }
+  }
 }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUserTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUserTest.kt
index 973a7d8c2a7ac45c77fbb20543660cdd0be6ba4e..15528dc226801a1dded49dd1b0963293b741589b 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUserTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IrcUserTest.kt
@@ -13,7 +13,10 @@ import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.syncables.state.IrcUserState
 import de.justjanne.libquassel.protocol.testutil.nextIrcUser
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Nested
 import org.junit.jupiter.api.Test
+import org.threeten.bp.Instant
 import kotlin.random.Random
 
 class IrcUserTest {
@@ -26,7 +29,7 @@ class IrcUserTest {
       host = "host"
     )
     val actual = IrcUser(state = state).apply {
-      fromVariantMap(emptyMap())
+      update(emptyMap())
     }.state()
 
     assertEquals(state, actual)
@@ -45,9 +48,215 @@ class IrcUserTest {
         host = expected.host
       )
     ).apply {
-      fromVariantMap(IrcUser(state = expected).toVariantMap())
+      update(IrcUser(state = expected).toVariantMap())
     }.state()
 
     assertEquals(expected, actual)
   }
+
+  @Nested
+  inner class Setters {
+    @Test
+    fun testHostMask() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      val nick = user.nick()
+      assertNotEquals("$nick!user@host", user.hostMask())
+      user.updateHostmask("$nick!user@host")
+      assertEquals("$nick!user@host", user.hostMask())
+    }
+
+    @Test
+    fun testAddUserModes() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      user.setUserModes("abc")
+      assertEquals(setOf('a', 'b', 'c'), user.userModes())
+      user.addUserModes("ef")
+      assertEquals(setOf('a', 'b', 'c', 'e', 'f'), user.userModes())
+    }
+
+    @Test
+    fun testRemoveUserModes() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      user.setUserModes("abc")
+      assertEquals(setOf('a', 'b', 'c'), user.userModes())
+      user.removeUserModes("ac")
+      assertEquals(setOf('b'), user.userModes())
+    }
+
+    @Test
+    fun testUserUnverified() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("~newuser", user.user())
+      assertNotEquals(null, user.verifiedUser())
+      user.setUser("~newuser")
+      assertEquals("~newuser", user.user())
+      assertEquals(null, user.verifiedUser())
+    }
+
+    @Test
+    fun testUserVerified() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("newuser", user.user())
+      assertNotEquals("newuser", user.verifiedUser())
+      user.setUser("newuser")
+      assertEquals("newuser", user.user())
+      assertEquals("newuser", user.verifiedUser())
+    }
+
+    @Test
+    fun testHost() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("TeraPro33-41.LowerMyBills.com", user.host())
+      user.setHost("TeraPro33-41.LowerMyBills.com")
+      assertEquals("TeraPro33-41.LowerMyBills.com", user.host())
+    }
+
+    @Test
+    fun testRealName() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("Bruce Wayne", user.realName())
+      user.setRealName("Bruce Wayne")
+      assertEquals("Bruce Wayne", user.realName())
+    }
+
+    @Test
+    fun testAccount() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("thebatman", user.account())
+      user.setAccount("thebatman")
+      assertEquals("thebatman", user.account())
+    }
+
+    @Test
+    fun testAway() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      user.setAway(false)
+      assertEquals(false, user.isAway())
+      user.setAway(true)
+      assertEquals(true, user.isAway())
+    }
+
+    @Test
+    fun testAwayMessage() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("I’ll be back", user.awayMessage())
+      user.setAwayMessage("I’ll be back")
+      assertEquals("I’ll be back", user.awayMessage())
+    }
+
+    @Test
+    fun testIdleTime() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      val timestamp = Instant.ofEpochSecond(1614642922)
+      assertNotEquals(timestamp, user.idleTime())
+      user.setIdleTime(timestamp)
+      assertEquals(timestamp, user.idleTime())
+    }
+
+    @Test
+    fun testLoginTime() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      val timestamp = Instant.ofEpochSecond(1614642922)
+      assertNotEquals(timestamp, user.loginTime())
+      user.setLoginTime(timestamp)
+      assertEquals(timestamp, user.loginTime())
+    }
+
+    @Test
+    fun testIrcOperator() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("lorem ipsum i dolor sit amet", user.ircOperator())
+      user.setIrcOperator("lorem ipsum i dolor sit amet")
+      assertEquals("lorem ipsum i dolor sit amet", user.ircOperator())
+    }
+
+    @Test
+    fun testLastAwayMessage() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      val timestamp = Instant.ofEpochSecond(1614642922)
+      assertNotEquals(timestamp, user.lastAwayMessageTime())
+      user.setLastAwayMessage(timestamp.epochSecond.toInt())
+      assertEquals(timestamp, user.lastAwayMessageTime())
+    }
+
+    @Test
+    fun testLastAwayMessageTime() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      val timestamp = Instant.ofEpochSecond(1614642922)
+      assertNotEquals(timestamp, user.lastAwayMessageTime())
+      user.setLastAwayMessageTime(timestamp)
+      assertEquals(timestamp, user.lastAwayMessageTime())
+    }
+
+    @Test
+    fun testWhoisServiceReply() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("lorem ipsum i dolor sit amet", user.whoisServiceReply())
+      user.setWhoisServiceReply("lorem ipsum i dolor sit amet")
+      assertEquals("lorem ipsum i dolor sit amet", user.whoisServiceReply())
+    }
+
+    @Test
+    fun testSuserHost() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("lorem ipsum i dolor sit amet", user.suserHost())
+      user.setSuserHost("lorem ipsum i dolor sit amet")
+      assertEquals("lorem ipsum i dolor sit amet", user.suserHost())
+    }
+
+    @Test
+    fun testEncrypted() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      user.setEncrypted(false)
+      assertEquals(false, user.isEncrypted())
+      user.setEncrypted(true)
+      assertEquals(true, user.isEncrypted())
+    }
+
+    @Test
+    fun testServer() {
+      val random = Random(1337)
+      val user = IrcUser(state = random.nextIrcUser(NetworkId(random.nextInt())))
+
+      assertNotEquals("orwell.freenode.net", user.server())
+      user.setServer("orwell.freenode.net")
+      assertEquals("orwell.freenode.net", user.server())
+    }
+  }
 }
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
index fe4bb8f13d732673d3eb1c7248b0d3f4c33fac54..99caa070e9fe801d153823d03f048e5368882aee 100644
--- 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
@@ -9,23 +9,47 @@
 
 package de.justjanne.libquassel.protocol.syncables
 
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.models.network.ChannelModeType
+import de.justjanne.libquassel.protocol.models.network.ConnectionState
+import de.justjanne.libquassel.protocol.models.network.NetworkServer
+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.NetworkState
+import de.justjanne.libquassel.protocol.testutil.MockSession
 import de.justjanne.libquassel.protocol.testutil.nextNetwork
 import de.justjanne.libquassel.protocol.testutil.nextString
+import de.justjanne.libquassel.protocol.variant.qVariant
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.Nested
 import org.junit.jupiter.api.Test
 import kotlin.random.Random
-import kotlin.test.assertNotEquals
 
 class NetworkTest {
   @Test
   fun testEmpty() {
     val state = NetworkState(networkId = NetworkId(1))
     val actual = Network(state = state).apply {
-      fromVariantMap(emptyMap())
+      update(emptyMap())
+    }.state()
+
+    assertEquals(state, actual)
+  }
+
+  @Test
+  fun testInvalid() {
+    val state = NetworkState(networkId = NetworkId(1))
+    val actual = Network(state = state).apply {
+      update(
+        mapOf(
+          "connectionState" to qVariant(-2, QtType.Int),
+        )
+      )
     }.state()
 
     assertEquals(state, actual)
@@ -38,33 +62,397 @@ class NetworkTest {
     val expected = random.nextNetwork(networkId)
 
     val actual = Network(state = NetworkState(networkId = networkId)).apply {
-      fromVariantMap(Network(state = expected).toVariantMap())
+      update(Network(state = expected).toVariantMap())
     }.state()
 
     assertEquals(expected, actual)
   }
 
+  @Nested
+  inner class Setters {
+    @Test
+    fun testIdentity() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(IdentityId(4), network.identity())
+      network.setIdentity(IdentityId(4))
+      assertEquals(IdentityId(4), network.identity())
+    }
+
+    @Test
+    fun testMyNick() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("justJanne", network.myNick())
+      network.setMyNick("justJanne")
+      assertEquals("justJanne", network.myNick())
+    }
+
+    @Test
+    fun testLatency() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(500, network.latency())
+      network.setLatency(500)
+      assertEquals(500, network.latency())
+    }
+
+    @Test
+    fun testNetworkName() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("Freenode", network.networkName())
+      network.setNetworkName("Freenode")
+      assertEquals("Freenode", network.networkName())
+    }
+
+    @Test
+    fun testCurrentServer() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("irc.freenode.org", network.currentServer())
+      network.setCurrentServer("irc.freenode.org")
+      assertEquals("irc.freenode.org", network.currentServer())
+    }
+
+    @Test
+    fun testConnectionStateValid() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(ConnectionState.Initializing, network.connectionState())
+      network.setConnectionState(ConnectionState.Initializing.value)
+      assertEquals(ConnectionState.Initializing, network.connectionState())
+    }
+
+    @Test
+    fun testConnectionStateInvalid() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(ConnectionState.Disconnected, network.connectionState())
+      network.setConnectionState(-2)
+      assertEquals(ConnectionState.Disconnected, network.connectionState())
+    }
+
+    @Test
+    fun testServerList() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      val desired = listOf(
+        NetworkServer(
+          host = "irc.freenode.org",
+          port = 6697u,
+          useSsl = true,
+          sslVerify = true,
+        ),
+        NetworkServer(
+          host = "irc.freenode.org",
+          port = 6667u,
+          useSsl = false,
+          sslVerify = false,
+        )
+      )
+      assertNotEquals(desired, network.serverList())
+      network.setServerList(
+        desired.map {
+          qVariant(it, QuasselType.NetworkServer)
+        }
+      )
+      assertEquals(desired, network.serverList())
+    }
+
+    @Test
+    fun testUseRandomServer() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUseRandomServer(false)
+      assertEquals(false, network.useRandomServer())
+      network.setUseRandomServer(true)
+      assertEquals(true, network.useRandomServer())
+    }
+
+    @Test
+    fun testPerform() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      val value = listOf(
+        "/wait 5; /ns ghost",
+        null,
+        "/mode -x"
+      )
+
+      val desired = listOf(
+        "/wait 5; /ns ghost",
+        "",
+        "/mode -x"
+      )
+
+      assertNotEquals(desired, network.perform())
+      network.setPerform(value)
+      assertEquals(desired, network.perform())
+    }
+
+    @Test
+    fun testUseAutoIdentify() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUseAutoIdentify(false)
+      assertEquals(false, network.useAutoIdentify())
+      network.setUseAutoIdentify(true)
+      assertEquals(true, network.useAutoIdentify())
+    }
+
+    @Test
+    fun testAutoIdentifyPassword() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("hunter2", network.autoIdentifyPassword())
+      network.setAutoIdentifyPassword("hunter2")
+      assertEquals("hunter2", network.autoIdentifyPassword())
+    }
+
+    @Test
+    fun testAutoIdentifyService() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("NickServ", network.autoIdentifyService())
+      network.setAutoIdentifyService("NickServ")
+      assertEquals("NickServ", network.autoIdentifyService())
+    }
+
+    @Test
+    fun testUseSasl() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUseSasl(false)
+      assertEquals(false, network.useSasl())
+      network.setUseSasl(true)
+      assertEquals(true, network.useSasl())
+    }
+
+    @Test
+    fun testSaslAccount() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("AzureDiamond", network.saslAccount())
+      network.setSaslAccount("AzureDiamond")
+      assertEquals("AzureDiamond", network.saslAccount())
+    }
+
+    @Test
+    fun testSaslPassword() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("hunter2", network.saslPassword())
+      network.setSaslPassword("hunter2")
+      assertEquals("hunter2", network.saslPassword())
+    }
+
+    @Test
+    fun testUseAutoReconnect() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUseAutoReconnect(false)
+      assertEquals(false, network.useAutoReconnect())
+      network.setUseAutoReconnect(true)
+      assertEquals(true, network.useAutoReconnect())
+    }
+
+    @Test
+    fun testAutoReconnectInterval() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(2500u, network.autoReconnectInterval())
+      network.setAutoReconnectInterval(2500u)
+      assertEquals(2500u, network.autoReconnectInterval())
+    }
+
+    @Test
+    fun testAutoReconnectRetries() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(7u.toUShort(), network.autoReconnectRetries())
+      network.setAutoReconnectRetries(7u.toUShort())
+      assertEquals(7u.toUShort(), network.autoReconnectRetries())
+    }
+
+    @Test
+    fun testUnlimitedReconnectRetries() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUnlimitedReconnectRetries(false)
+      assertEquals(false, network.unlimitedReconnectRetries())
+      network.setUnlimitedReconnectRetries(true)
+      assertEquals(true, network.unlimitedReconnectRetries())
+    }
+
+    @Test
+    fun testRejoinChannels() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setRejoinChannels(false)
+      assertEquals(false, network.rejoinChannels())
+      network.setRejoinChannels(true)
+      assertEquals(true, network.rejoinChannels())
+    }
+
+    @Test
+    fun testUseCustomMessageRate() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUseCustomMessageRate(false)
+      assertEquals(false, network.useCustomMessageRate())
+      network.setUseCustomMessageRate(true)
+      assertEquals(true, network.useCustomMessageRate())
+    }
+
+    @Test
+    fun testMessageRateBurstSize() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(20u, network.messageRateBurstSize())
+      network.setMessageRateBurstSize(20u)
+      assertEquals(20u, network.messageRateBurstSize())
+    }
+
+    @Test
+    fun testMessageRateDelay() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals(1200u, network.messageRateDelay())
+      network.setMessageRateDelay(1200u)
+      assertEquals(1200u, network.messageRateDelay())
+    }
+
+    @Test
+    fun testUnlimitedMessageRate() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      network.setUnlimitedMessageRate(false)
+      assertEquals(false, network.unlimitedMessageRate())
+      network.setUnlimitedMessageRate(true)
+      assertEquals(true, network.unlimitedMessageRate())
+    }
+
+    @Test
+    fun testCodecForServer() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("UTF_8", network.codecForServer())
+      network.setCodecForServer(StringSerializerUtf8.serializeRaw("UTF_8"))
+      assertEquals("UTF_8", network.codecForServer())
+      network.setCodecForServer(StringSerializerUtf8.serializeRaw("ISO_8859_1"))
+      assertEquals("ISO_8859_1", network.codecForServer())
+    }
+
+    @Test
+    fun testCodecForEncoding() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("UTF_8", network.codecForEncoding())
+      network.setCodecForEncoding(StringSerializerUtf8.serializeRaw("UTF_8"))
+      assertEquals("UTF_8", network.codecForEncoding())
+      network.setCodecForEncoding(StringSerializerUtf8.serializeRaw("ISO_8859_1"))
+      assertEquals("ISO_8859_1", network.codecForEncoding())
+    }
+
+    @Test
+    fun testCodecForDecoding() {
+      val random = Random(1337)
+      val network = Network(state = random.nextNetwork(NetworkId(random.nextInt())))
+
+      assertNotEquals("UTF_8", network.codecForDecoding())
+      network.setCodecForDecoding(StringSerializerUtf8.serializeRaw("UTF_8"))
+      assertEquals("UTF_8", network.codecForDecoding())
+      network.setCodecForDecoding(StringSerializerUtf8.serializeRaw("ISO_8859_1"))
+      assertEquals("ISO_8859_1", network.codecForDecoding())
+    }
+  }
+
   @Nested
   inner class User {
     @Test
     fun addNew() {
+      val random = Random(1337)
+      val session = NetworkMockSession()
+      val network = Network(session, state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
+
+      val sizeBefore = network.ircUserCount()
+      assertNotEquals(0, sizeBefore)
+      val userName = random.nextString()
+      assertFalse(network.nicks().contains(userName))
+      assertFalse(session.synchronizeCalls.contains(network.ircUser(userName) as SyncableObject?))
+      network.addIrcUser(userName)
+      assertEquals(sizeBefore + 1, network.ircUserCount())
+      assertTrue(network.nicks().contains(userName))
+      assertTrue(session.synchronizeCalls.contains(network.ircUser(userName) as SyncableObject?))
+    }
+
+    @Test
+    fun addNewOffline() {
       val random = Random(1337)
       val network = Network(state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
 
       val sizeBefore = network.ircUserCount()
       assertNotEquals(0, sizeBefore)
-      network.addIrcUser(random.nextString())
+      val userName = random.nextString()
+      assertFalse(network.nicks().contains(userName))
+      network.addIrcUser(userName)
       assertEquals(sizeBefore + 1, network.ircUserCount())
+      assertTrue(network.nicks().contains(userName))
     }
 
     @Test
     fun addExisting() {
+      val random = Random(1337)
+      val session = NetworkMockSession()
+      val network = Network(session, state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
+
+      assertNotEquals(0, network.ircUserCount())
+      val user = network.ircUsers().first()
+      assertTrue(network.nicks().contains(user.nick()))
+      assertFalse(session.synchronizeCalls.contains(network.ircUser(user.nick()) as SyncableObject?))
+      assertEquals(user, network.newIrcUser(user.hostMask()))
+      assertTrue(network.nicks().contains(user.nick()))
+      assertFalse(session.synchronizeCalls.contains(network.ircUser(user.nick()) as SyncableObject?))
+    }
+
+    @Test
+    fun addExistingOffline() {
       val random = Random(1337)
       val network = Network(state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
 
       assertNotEquals(0, network.ircUserCount())
-      val existing = network.ircUsers().first()
-      assertEquals(existing, network.newIrcUser(existing.hostMask()))
+      val user = network.ircUsers().first()
+      assertTrue(network.nicks().contains(user.nick()))
+      assertEquals(user, network.newIrcUser(user.hostMask()))
+      assertTrue(network.nicks().contains(user.nick()))
     }
 
     @Test
@@ -74,8 +462,11 @@ class NetworkTest {
 
       val sizeBefore = network.ircUserCount()
       assertNotEquals(0, sizeBefore)
-      network.removeIrcUser(network.ircUsers().first())
+      val user = network.ircUsers().first()
+      assertTrue(network.nicks().contains(user.nick()))
+      network.removeIrcUser(user)
       assertEquals(sizeBefore - 1, network.ircUserCount())
+      assertFalse(network.nicks().contains(user.nick()))
     }
   }
 
@@ -83,17 +474,47 @@ class NetworkTest {
   inner class Channel {
     @Test
     fun addNew() {
+      val random = Random(1337)
+      val session = NetworkMockSession()
+      val network = Network(session, state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
+
+      val sizeBefore = network.ircChannelCount()
+      assertNotEquals(0, sizeBefore)
+      val channelName = random.nextString()
+      assertFalse(session.synchronizeCalls.contains(network.ircChannel(channelName) as SyncableObject?))
+      network.addIrcChannel(channelName)
+      assertEquals(sizeBefore + 1, network.ircChannelCount())
+      assertTrue(network.channels().contains(channelName))
+      assertTrue(session.synchronizeCalls.contains(network.ircChannel(channelName) as SyncableObject?))
+    }
+    @Test
+    fun addNewOffline() {
       val random = Random(1337)
       val network = Network(state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
 
       val sizeBefore = network.ircChannelCount()
       assertNotEquals(0, sizeBefore)
-      network.addIrcChannel(random.nextString())
+      val channelName = random.nextString()
+      network.addIrcChannel(channelName)
       assertEquals(sizeBefore + 1, network.ircChannelCount())
+      assertTrue(network.channels().contains(channelName))
     }
 
     @Test
     fun addExisting() {
+      val random = Random(1337)
+      val session = NetworkMockSession()
+      val network = Network(session, state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
+
+      assertNotEquals(0, network.ircUserCount())
+      val existing = network.ircChannels().first()
+      assertFalse(session.synchronizeCalls.contains(network.ircChannel(existing.name()) as SyncableObject?))
+      assertEquals(existing, network.newIrcChannel(existing.name()))
+      assertFalse(session.synchronizeCalls.contains(network.ircChannel(existing.name()) as SyncableObject?))
+    }
+
+    @Test
+    fun addExistingOffline() {
       val random = Random(1337)
       val network = Network(state = random.nextNetwork(networkId = NetworkId(random.nextInt())))
 
@@ -123,8 +544,14 @@ class NetworkTest {
 
       val sizeBefore = network.supports().size
       assertNotEquals(0, sizeBefore)
-      network.addSupport(random.nextString(), random.nextString())
+      val key = random.nextString()
+      val value = random.nextString()
+      assertFalse(network.supports(key))
+      assertNotEquals(value, network.supportValue(key))
+      network.addSupport(key, value)
       assertEquals(sizeBefore + 1, network.supports().size)
+      assertTrue(network.supports(key))
+      assertEquals(value, network.supportValue(key))
     }
 
     @Test
@@ -134,8 +561,14 @@ class NetworkTest {
 
       val sizeBefore = network.supports().size
       assertNotEquals(0, sizeBefore)
-      network.addSupport(network.supports().keys.first(), random.nextString())
+      val key = network.supports().keys.first()
+      val value = random.nextString()
+      assertTrue(network.supports(key))
+      assertNotEquals(value, network.supportValue(key))
+      network.addSupport(key, value)
       assertEquals(sizeBefore, network.supports().size)
+      assertTrue(network.supports(key))
+      assertEquals(value, network.supportValue(key))
     }
 
     @Test
@@ -145,8 +578,12 @@ class NetworkTest {
 
       val sizeBefore = network.supports().size
       assertNotEquals(0, sizeBefore)
-      network.removeSupport(network.supports().keys.first())
+      val key = network.supports().keys.first()
+      assertTrue(network.supports(key))
+      network.removeSupport(key)
       assertEquals(sizeBefore - 1, network.supports().size)
+      assertFalse(network.supports(key))
+      assertEquals(null, network.supportValue(key))
     }
   }
 
@@ -159,8 +596,14 @@ class NetworkTest {
 
       val sizeBefore = network.caps().size
       assertNotEquals(0, sizeBefore)
-      network.addCap(random.nextString(), random.nextString())
+      val key = random.nextString()
+      val value = random.nextString()
+      assertFalse(network.capAvailable(key))
+      assertNotEquals(value, network.capValue(key))
+      network.addCap(key, value)
       assertEquals(sizeBefore + 1, network.caps().size)
+      assertTrue(network.capAvailable(key))
+      assertEquals(value, network.capValue(key))
     }
 
     @Test
@@ -170,8 +613,14 @@ class NetworkTest {
 
       val sizeBefore = network.caps().size
       assertNotEquals(0, sizeBefore)
-      network.addCap(network.caps().keys.first(), random.nextString())
+      val key = network.caps().keys.first()
+      val value = random.nextString()
+      assertTrue(network.capAvailable(key))
+      assertNotEquals(value, network.capValue(key))
+      network.addCap(key, value)
       assertEquals(sizeBefore, network.caps().size)
+      assertTrue(network.capAvailable(key))
+      assertEquals(value, network.capValue(key))
     }
 
     @Test
@@ -181,8 +630,11 @@ class NetworkTest {
 
       val sizeBefore = network.capsEnabled().size
       assertNotEquals(0, sizeBefore)
-      network.acknowledgeCap(random.nextString())
+      val key = random.nextString()
+      assertFalse(network.capEnabled(key))
+      network.acknowledgeCap(key)
       assertEquals(sizeBefore + 1, network.capsEnabled().size)
+      assertTrue(network.capEnabled(key))
     }
 
     @Test
@@ -192,8 +644,11 @@ class NetworkTest {
 
       val sizeBefore = network.capsEnabled().size
       assertNotEquals(0, sizeBefore)
-      network.acknowledgeCap(network.capsEnabled().first())
+      val key = network.capsEnabled().first()
+      assertTrue(network.capEnabled(key))
+      network.acknowledgeCap(key)
       assertEquals(sizeBefore, network.capsEnabled().size)
+      assertTrue(network.capEnabled(key))
     }
 
     @Test
@@ -244,6 +699,19 @@ class NetworkTest {
         ),
         network.channelModes()
       )
+
+      for (c in setOf('e', 'I', 'b', 'q')) {
+        assertEquals(ChannelModeType.A_CHANMODE, network.channelModeType(c))
+      }
+      for (c in setOf('k')) {
+        assertEquals(ChannelModeType.B_CHANMODE, network.channelModeType(c))
+      }
+      for (c in setOf('f', 'l', 'j')) {
+        assertEquals(ChannelModeType.C_CHANMODE, network.channelModeType(c))
+      }
+      for (c in setOf('C', 'F', 'L', 'M', 'P', 'Q', 'S', 'c', 'g', 'i', 'm', 'n', 'p', 'r', 's', 't', 'u', 'z')) {
+        assertEquals(ChannelModeType.D_CHANMODE, network.channelModeType(c))
+      }
     }
 
     @Test
@@ -445,4 +913,12 @@ class NetworkTest {
       )
     }
   }
+
+  class NetworkMockSession : MockSession() {
+    val synchronizeCalls = mutableListOf<SyncableObject>()
+
+    override fun synchronize(it: SyncableObject) {
+      synchronizeCalls.add(it)
+    }
+  }
 }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/MockSession.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/MockSession.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fc408f33a7a49852245798c77658083da4724ae9
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/MockSession.kt
@@ -0,0 +1,95 @@
+/*
+ * libquassel
+ * Copyright (c) 2021 Janne Mareike Koschinski
+ *
+ * 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.annotations.ProtocolSide
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.models.ids.IdentityId
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.syncables.AliasManager
+import de.justjanne.libquassel.protocol.syncables.BufferSyncer
+import de.justjanne.libquassel.protocol.syncables.BufferViewManager
+import de.justjanne.libquassel.protocol.syncables.CoreInfo
+import de.justjanne.libquassel.protocol.syncables.DccConfig
+import de.justjanne.libquassel.protocol.syncables.HighlightRuleManager
+import de.justjanne.libquassel.protocol.syncables.Identity
+import de.justjanne.libquassel.protocol.syncables.Network
+import de.justjanne.libquassel.protocol.syncables.NetworkConfig
+import de.justjanne.libquassel.protocol.syncables.ObjectRepository
+import de.justjanne.libquassel.protocol.syncables.Session
+import de.justjanne.libquassel.protocol.syncables.SyncableObject
+import de.justjanne.libquassel.protocol.syncables.stubs.BacklogManagerStub
+import de.justjanne.libquassel.protocol.syncables.stubs.IgnoreListManagerStub
+import de.justjanne.libquassel.protocol.syncables.stubs.IrcListHelperStub
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+
+abstract class MockSession : Session {
+  override val protocolSide: ProtocolSide
+    get() = TODO("Mock Implementation")
+  override val objectRepository: ObjectRepository
+    get() = TODO("Mock Implementation")
+
+  override fun network(id: NetworkId): Network? = TODO("Mock Implementation")
+
+  override fun identity(id: IdentityId): Identity = TODO("Mock Implementation")
+
+  override fun aliasManager(): AliasManager = TODO("Mock Implementation")
+
+  override fun bufferSyncer(): BufferSyncer = TODO("Mock Implementation")
+
+  override fun backlogManager(): BacklogManagerStub = TODO("Mock Implementation")
+
+  override fun bufferViewManager(): BufferViewManager = TODO("Mock Implementation")
+
+  override fun ignoreListManager(): IgnoreListManagerStub = TODO("Mock Implementation")
+
+  override fun highlightRuleManager(): HighlightRuleManager = TODO("Mock Implementation")
+
+  override fun ircListHelper(): IrcListHelperStub = TODO("Mock Implementation")
+
+  override fun coreInfo(): CoreInfo = TODO("Mock Implementation")
+
+  override fun dccConfig(): DccConfig = TODO("Mock Implementation")
+
+  override fun networkConfig(): NetworkConfig = TODO("Mock Implementation")
+
+  override fun synchronize(it: SyncableObject): Unit = TODO("Mock Implementation")
+
+  override fun stopSynchronize(it: SyncableObject): Unit = TODO("Mock Implementation")
+
+  override fun emit(message: SignalProxyMessage): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.Sync): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.Rpc): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.InitRequest): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.InitData): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.HeartBeat): Unit = TODO("Mock Implementation")
+
+  override fun dispatch(message: SignalProxyMessage.HeartBeatReply): Unit = TODO("Mock Implementation")
+
+  override val className: String
+    get() = TODO("Mock Implementation")
+  override val objectName: String
+    get() = TODO("Mock Implementation")
+  override val initialized: Boolean
+    get() = TODO("Mock Implementation")
+  override val session: Session?
+    get() = TODO("Mock Implementation")
+
+  override fun fromVariantMap(properties: QVariantMap): Unit = TODO("Mock Implementation")
+
+  override fun toVariantMap(): QVariantMap = TODO("Mock Implementation")
+}