diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BufferActivity.kt
similarity index 53%
rename from libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt
rename to libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BufferActivity.kt
index 7b106be66c411f9b9aa418b7dd79bc78aa262860..6f6b274840f66838d87ba375241f7884329a2623 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/flags/BufferActivity.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/BufferActivity.kt
@@ -7,41 +7,39 @@
  * obtain one at https://mozilla.org/MPL/2.0/.
  */
 
-package de.justjanne.libquassel.protocol.models.flags
-
-import de.justjanne.bitflags.Flag
-import de.justjanne.bitflags.Flags
-import de.justjanne.bitflags.toEnumSet
+package de.justjanne.libquassel.protocol.models
 
 /**
  * Model representing all seen activity on a buffer
  */
 enum class BufferActivity(
-  override val value: UInt,
-) : Flag<UInt> {
+  /**
+   * Underlying representation
+   */
+  val value: Int,
+) {
   /**
    * Other, unspecified activity has occurred on this buffer (join, part, quit, etc)
    */
-  OtherActivity(0x01u),
+  OtherActivity(1),
 
   /**
    * A new unread mesage is available on this buffer
    */
-  NewMessage(0x02u),
+  NewMessage(2),
 
   /**
    * A highlight for the current user is available on this buffer
    */
-  Highlight(0x04u);
+  Highlight(4);
 
-  companion object : Flags<UInt, BufferActivity> {
-    private val values = enumValues<BufferActivity>()
+  companion object {
+    private val map = enumValues<BufferActivity>()
       .associateBy(BufferActivity::value)
-    override val all: BufferActivities = values.values.toEnumSet()
+
+    /**
+     * Obtain a zone specification by its underlying representation
+     */
+    fun of(type: Int) = map[type]
   }
 }
-
-/**
- * Model representing a bitfield of [BufferActivity] flags
- */
-typealias BufferActivities = Set<BufferActivity>
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
index ad98e36a9458e1b30ebe50cefde68b6a0dd20de7..60b878ec966aa060f16d8837b18a9c9fe409a06c 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/BufferViewConfig.kt
@@ -11,8 +11,8 @@ package de.justjanne.libquassel.protocol.syncables
 
 import de.justjanne.bitflags.of
 import de.justjanne.bitflags.toBits
+import de.justjanne.libquassel.protocol.models.BufferActivity
 import de.justjanne.libquassel.protocol.models.BufferInfo
-import de.justjanne.libquassel.protocol.models.flags.BufferActivity
 import de.justjanne.libquassel.protocol.models.flags.BufferType
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
@@ -43,7 +43,7 @@ open class BufferViewConfig(
           ?.mapNotNull { it.into<BufferId>() }
           ?.toSet()
           .orEmpty(),
-        temporarilyRemovedBuffers = properties["TemporarilyRemovedBuffers"].into<QVariantList>()
+        hiddenBuffers = properties["TemporarilyRemovedBuffers"].into<QVariantList>()
           ?.mapNotNull { it.into<BufferId>() }
           ?.toSet()
           .orEmpty(),
@@ -59,7 +59,6 @@ open class BufferViewConfig(
           ?.let(BufferType.Companion::of)
           ?: allowedBufferTypes,
         minimumActivity = properties["minimumActivity"].into<Int>()
-          ?.let(Int::toUInt)
           ?.let(BufferActivity.Companion::of)
           ?: minimumActivity,
         showSearch = properties["showSearch"].into(showSearch),
@@ -81,7 +80,7 @@ open class BufferViewConfig(
       QtType.QVariantList
     ),
     "TemporarilyRemovedBuffers" to qVariant(
-      temporarilyRemovedBuffers().map {
+      hiddenBuffers().map {
         qVariant(it, QuasselType.BufferId)
       },
       QtType.QVariantList
@@ -94,7 +93,7 @@ open class BufferViewConfig(
     "hideInactiveNetworks" to qVariant(hideInactiveNetworks(), QtType.Bool),
     "disableDecoration" to qVariant(disableDecoration(), QtType.Bool),
     "allowedBufferTypes" to qVariant(allowedBufferTypes().toBits().toInt(), QtType.Int),
-    "minimumActivity" to qVariant(minimumActivity().toBits().toInt(), QtType.Int),
+    "minimumActivity" to qVariant(minimumActivity()?.value?.toInt() ?: 0, QtType.Int),
     "showSearch" to qVariant(showSearch(), QtType.Bool)
   )
 
@@ -112,42 +111,46 @@ open class BufferViewConfig(
 
   fun buffers() = state().buffers
   fun removedBuffers() = state().removedBuffers
-  fun temporarilyRemovedBuffers() = state().temporarilyRemovedBuffers
+  fun hiddenBuffers() = state().hiddenBuffers
 
   override fun addBuffer(buffer: BufferId, pos: Int) {
+    if (buffers().contains(buffer)) {
+      return
+    }
+
     state.update {
       copy(
         buffers = buffers.insert(buffer, pos),
         removedBuffers = removedBuffers - buffer,
-        temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
+        hiddenBuffers = hiddenBuffers - buffer
       )
     }
 
     super.addBuffer(buffer, pos)
   }
 
-  override fun removeBuffer(buffer: BufferId) {
+  override fun hideBuffer(buffer: BufferId) {
     state.update {
       copy(
         buffers = buffers - buffer,
         removedBuffers = removedBuffers - buffer,
-        temporarilyRemovedBuffers = temporarilyRemovedBuffers + buffer
+        hiddenBuffers = hiddenBuffers + buffer
       )
     }
 
-    super.removeBuffer(buffer)
+    super.hideBuffer(buffer)
   }
 
-  override fun removeBufferPermanently(buffer: BufferId) {
+  override fun removeBuffer(buffer: BufferId) {
     state.update {
       copy(
         buffers = buffers - buffer,
         removedBuffers = removedBuffers + buffer,
-        temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
+        hiddenBuffers = hiddenBuffers - buffer
       )
     }
 
-    super.removeBufferPermanently(buffer)
+    super.removeBuffer(buffer)
   }
 
   override fun moveBuffer(buffer: BufferId, pos: Int) {
@@ -159,7 +162,7 @@ open class BufferViewConfig(
       copy(
         buffers = buffers.move(buffer, pos),
         removedBuffers = removedBuffers - buffer,
-        temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
+        hiddenBuffers = hiddenBuffers - buffer
       )
     }
 
@@ -210,7 +213,7 @@ open class BufferViewConfig(
 
   override fun setMinimumActivity(value: Int) {
     state.update {
-      copy(minimumActivity = BufferActivity.of(value.toUInt()))
+      copy(minimumActivity = BufferActivity.of(value))
     }
     super.setMinimumActivity(value)
   }
@@ -259,14 +262,14 @@ open class BufferViewConfig(
   fun handleBuffer(info: BufferInfo, unhide: Boolean = false) {
     if (addNewBuffersAutomatically() &&
       !buffers().contains(info.bufferId) &&
-      !temporarilyRemovedBuffers().contains(info.bufferId) &&
+      !hiddenBuffers().contains(info.bufferId) &&
       !removedBuffers().contains(info.bufferId) &&
       !info.type.contains(BufferType.Status)
     ) {
       insertBufferSorted(info)
     } else if (unhide &&
       !buffers().contains(info.bufferId) &&
-      temporarilyRemovedBuffers().contains(info.bufferId)
+      hiddenBuffers().contains(info.bufferId)
     ) {
       insertBufferSorted(info)
     }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
index 16ade00a5cc60592780de291c21fa17c0d481f7a..bfd6d0c39e7628e5923baae6859cad78ca23827f 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManager.kt
@@ -18,6 +18,7 @@ import de.justjanne.libquassel.protocol.models.rules.StrictnessType
 import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.syncables.state.IgnoreListManagerState
 import de.justjanne.libquassel.protocol.syncables.stubs.IgnoreListManagerStub
+import de.justjanne.libquassel.protocol.util.collections.removeAt
 import de.justjanne.libquassel.protocol.util.update
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariantMap
@@ -132,7 +133,7 @@ class IgnoreListManager(
   fun count() = state().count()
   fun removeAt(index: Int) {
     state.update {
-      copy(rules = rules.drop(index))
+      copy(rules = rules.removeAt(index))
     }
   }
 
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
index 7867743de65e320e44cfd9878118e0c1a3cc2db8..d47d37f6b7d13f42202df2cd9a4488e7aded3370 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/IrcChannel.kt
@@ -234,6 +234,7 @@ open class IrcChannel(
 
   override fun removeChannelMode(mode: Char, value: String?) {
     val network = session?.network(network())
+    println(network?.channelModeType(mode))
     state.update {
       copy(
         channelModes = channelModes.run {
@@ -243,13 +244,15 @@ open class IrcChannel(
                 "Mode $mode of ChannelModeType A must have a value"
               }
 
-              copy(a = a + Pair(mode, a[mode].orEmpty() - value))
+              val result = Pair(mode, a[mode].orEmpty() - value)
+              if (result.second.isNotEmpty()) copy(a = a + result)
+              else copy(a = a - mode)
             }
             ChannelModeType.B_CHANMODE -> {
               copy(b = b - mode)
             }
             ChannelModeType.C_CHANMODE -> {
-              copy(b = c - mode)
+              copy(c = c - mode)
             }
             ChannelModeType.D_CHANMODE ->
               copy(d = d - mode)
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/BufferViewConfigState.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/BufferViewConfigState.kt
index 5f8823368cade6d19f7522906b432cf5c55af46f..141716a85e5eb0b8e748c1753d393adb0822febd 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/BufferViewConfigState.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/state/BufferViewConfigState.kt
@@ -9,9 +9,7 @@
 
 package de.justjanne.libquassel.protocol.syncables.state
 
-import de.justjanne.bitflags.none
-import de.justjanne.libquassel.protocol.models.flags.BufferActivities
-import de.justjanne.libquassel.protocol.models.flags.BufferActivity
+import de.justjanne.libquassel.protocol.models.BufferActivity
 import de.justjanne.libquassel.protocol.models.flags.BufferType
 import de.justjanne.libquassel.protocol.models.flags.BufferTypes
 import de.justjanne.libquassel.protocol.models.ids.BufferId
@@ -27,9 +25,9 @@ data class BufferViewConfigState(
   val hideInactiveNetworks: Boolean = false,
   val disableDecoration: Boolean = false,
   val allowedBufferTypes: BufferTypes = BufferType.all,
-  val minimumActivity: BufferActivities = BufferActivity.none(),
+  val minimumActivity: BufferActivity? = null,
   val showSearch: Boolean = false,
   val buffers: List<BufferId> = emptyList(),
   val removedBuffers: Set<BufferId> = emptySet(),
-  val temporarilyRemovedBuffers: Set<BufferId> = emptySet(),
+  val hiddenBuffers: Set<BufferId> = emptySet(),
 )
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferViewConfigStub.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferViewConfigStub.kt
index 31544498a54968b33bcdb94373e7faeb3fd8720d..9fe8c77603ab51114ba43a6e61050416d79e1e0c 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferViewConfigStub.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/BufferViewConfigStub.kt
@@ -62,8 +62,8 @@ interface BufferViewConfigStub : SyncableStub {
     )
   }
 
-  @SyncedCall(target = ProtocolSide.CLIENT)
-  fun removeBuffer(buffer: BufferId) {
+  @SyncedCall(target = ProtocolSide.CLIENT, name = "removeBuffer")
+  fun hideBuffer(buffer: BufferId) {
     sync(
       target = ProtocolSide.CLIENT,
       "removeBuffer",
@@ -72,7 +72,7 @@ interface BufferViewConfigStub : SyncableStub {
   }
 
   @SyncedCall(target = ProtocolSide.CORE)
-  fun requestRemoveBuffer(buffer: BufferId) {
+  fun requestHideBuffer(buffer: BufferId) {
     sync(
       target = ProtocolSide.CORE,
       "requestRemoveBuffer",
@@ -80,8 +80,8 @@ interface BufferViewConfigStub : SyncableStub {
     )
   }
 
-  @SyncedCall(target = ProtocolSide.CLIENT)
-  fun removeBufferPermanently(buffer: BufferId) {
+  @SyncedCall(target = ProtocolSide.CLIENT, name = "removeBufferPermanently")
+  fun removeBuffer(buffer: BufferId) {
     sync(
       target = ProtocolSide.CLIENT,
       "removeBufferPermanently",
@@ -90,7 +90,7 @@ interface BufferViewConfigStub : SyncableStub {
   }
 
   @SyncedCall(target = ProtocolSide.CORE)
-  fun requestRemoveBufferPermanently(buffer: BufferId) {
+  fun requestRemoveBuffer(buffer: BufferId) {
     sync(
       target = ProtocolSide.CORE,
       "requestRemoveBufferPermanently",
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
index db54c8999ca90a0cfb4cbdfdaed699d19a16e5df..2df834d0dedc5982186a2e72145cbb5e9fe6afac 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/move.kt
@@ -13,9 +13,6 @@ fun <T> List<T>.move(value: T, pos: Int = size): List<T> {
   val newPos = pos.coerceIn(0, size)
   val oldPos = indexOf(value)
 
-  return when {
-    newPos > oldPos -> remove(value).insert(value, newPos - 1)
-    newPos < oldPos -> remove(value).insert(value, newPos)
-    else -> this
-  }
+  return if (newPos == oldPos) this
+  else remove(value).insert(value, newPos)
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
index 405dfa2c193c6d3041eba4d86777fbb45ed05e32..2aa1d58b3ff21c1348da36d23d00b3db15ff1519 100644
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
+++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/collections/remove.kt
@@ -10,3 +10,12 @@
 package de.justjanne.libquassel.protocol.util.collections
 
 fun <T> List<T>.remove(value: T): List<T> = this.filter { it != value }
+fun <T> List<T>.removeAt(index: Int): List<T> {
+  if (index < 0 || index >= size) return this
+
+  val before = subList(0, index)
+  val after = subList(index + 1, size)
+  if (before.isEmpty()) return after
+  if (after.isEmpty()) return before
+  return before + after
+}
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 00e208b03fca35ac5c73d1f8e789a7441516c353..d4c68d4c1379f61ebcb10ac3568220fdca2b7761 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
@@ -9,9 +9,17 @@
 
 package de.justjanne.libquassel.protocol.syncables
 
+import de.justjanne.bitflags.of
+import de.justjanne.bitflags.toBits
+import de.justjanne.libquassel.protocol.models.BufferActivity
+import de.justjanne.libquassel.protocol.models.flags.BufferType
+import de.justjanne.libquassel.protocol.models.ids.BufferId
+import de.justjanne.libquassel.protocol.models.ids.NetworkId
 import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
 import de.justjanne.libquassel.protocol.testutil.nextBufferViewConfig
 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
 
@@ -41,4 +49,435 @@ class BufferViewConfigTest {
 
     assertEquals(expected, actual)
   }
+
+  @Nested
+  inner class AddBuffer {
+    @Test
+    fun new() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = BufferId(105)
+      value.addBuffer(buffer, 3)
+      assertEquals(3, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize + 1, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun existing() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.buffers().first()
+      value.addBuffer(buffer, 3)
+      assertEquals(0, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun hidden() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.hiddenBuffers().first()
+      value.addBuffer(buffer, 3)
+      assertEquals(3, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize + 1, value.buffers().size)
+      assertEquals(hiddenSize - 1, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun removed() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.removedBuffers().first()
+      value.addBuffer(buffer, 3)
+      assertEquals(3, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize + 1, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize - 1, value.removedBuffers().size)
+    }
+  }
+
+  @Nested
+  inner class HideBuffer {
+    @Test
+    fun new() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = BufferId(105)
+      value.hideBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize + 1, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun existing() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.buffers().first()
+      value.hideBuffer(buffer)
+      assertEquals(bufferSize - 1, value.buffers().size)
+      assertEquals(hiddenSize + 1, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun hidden() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.hiddenBuffers().first()
+      value.hideBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun removed() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.removedBuffers().first()
+      value.hideBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize + 1, value.hiddenBuffers().size)
+      assertEquals(removedSize - 1, value.removedBuffers().size)
+    }
+  }
+
+  @Nested
+  inner class RemoveBuffer {
+    @Test
+    fun new() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = BufferId(105)
+      value.removeBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize + 1, value.removedBuffers().size)
+    }
+
+    @Test
+    fun existing() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.buffers().first()
+      value.removeBuffer(buffer)
+      assertEquals(bufferSize - 1, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize + 1, value.removedBuffers().size)
+    }
+
+    @Test
+    fun hidden() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.hiddenBuffers().first()
+      value.removeBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize - 1, value.hiddenBuffers().size)
+      assertEquals(removedSize + 1, value.removedBuffers().size)
+    }
+
+    @Test
+    fun removed() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.removedBuffers().first()
+      value.removeBuffer(buffer)
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+  }
+
+  @Nested
+  inner class MoveBuffer {
+    @Test
+    fun new() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = BufferId(105)
+      value.moveBuffer(buffer, 3)
+      assertEquals(-1, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun existing() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.buffers().first()
+      println(value.buffers())
+      value.moveBuffer(buffer, 3)
+      println(value.buffers())
+      assertEquals(3, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun hidden() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.hiddenBuffers().first()
+      value.moveBuffer(buffer, 3)
+      assertEquals(-1, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+
+    @Test
+    fun removed() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val bufferSize = value.buffers().size
+      val hiddenSize = value.hiddenBuffers().size
+      val removedSize = value.removedBuffers().size
+      val buffer = value.removedBuffers().first()
+      value.moveBuffer(buffer, 3)
+      assertEquals(-1, value.buffers().indexOf(buffer))
+      assertEquals(bufferSize, value.buffers().size)
+      assertEquals(hiddenSize, value.hiddenBuffers().size)
+      assertEquals(removedSize, value.removedBuffers().size)
+    }
+  }
+
+  @Nested
+  inner class Setters {
+    @Test
+    fun testBufferViewName() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val data = "All Chats"
+      assertNotEquals(data, value.bufferViewName())
+      value.setBufferViewName(data)
+      assertEquals(data, value.bufferViewName())
+    }
+
+    @Test
+    fun testAddNewBuffersAutomatically() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setAddNewBuffersAutomatically(false)
+      assertEquals(false, value.addNewBuffersAutomatically())
+      value.setAddNewBuffersAutomatically(true)
+      assertEquals(true, value.addNewBuffersAutomatically())
+    }
+
+    @Test
+    fun testAllowedBufferTypes() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val data = BufferType.of(
+        BufferType.Channel,
+        BufferType.Status,
+        BufferType.Query
+      )
+      assertNotEquals(data, value.allowedBufferTypes())
+      value.setAllowedBufferTypes(data.toBits().toInt())
+      assertEquals(data, value.allowedBufferTypes())
+    }
+
+    @Test
+    fun testDisableDecoration() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setDisableDecoration(false)
+      assertEquals(false, value.disableDecoration())
+      value.setDisableDecoration(true)
+      assertEquals(true, value.disableDecoration())
+    }
+
+    @Test
+    fun testHideInactiveBuffers() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setHideInactiveBuffers(false)
+      assertEquals(false, value.hideInactiveBuffers())
+      value.setHideInactiveBuffers(true)
+      assertEquals(true, value.hideInactiveBuffers())
+    }
+
+    @Test
+    fun testHideInactiveNetworks() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setHideInactiveNetworks(false)
+      assertEquals(false, value.hideInactiveNetworks())
+      value.setHideInactiveNetworks(true)
+      assertEquals(true, value.hideInactiveNetworks())
+    }
+
+    @Test
+    fun testMinimumActivity() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val data = BufferActivity.Highlight
+      assertNotEquals(data, value.minimumActivity())
+      value.setMinimumActivity(data.value)
+      assertEquals(data, value.minimumActivity())
+    }
+
+    @Test
+    fun testNetworkId() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      val data = NetworkId(random.nextInt())
+      assertNotEquals(data, value.networkId())
+      value.setNetworkId(data)
+      assertEquals(data, value.networkId())
+    }
+
+    @Test
+    fun testShowSearch() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setShowSearch(false)
+      assertEquals(false, value.showSearch())
+      value.setShowSearch(true)
+      assertEquals(true, value.showSearch())
+    }
+
+    @Test
+    fun testSortAlphabetically() {
+      val random = Random(1337)
+      val value = BufferViewConfig(
+        state = random.nextBufferViewConfig(bufferViewId = 1)
+      )
+
+      value.setSortAlphabetically(false)
+      assertEquals(false, value.sortAlphabetically())
+      value.setSortAlphabetically(true)
+      assertEquals(true, value.sortAlphabetically())
+    }
+  }
 }
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 7f611aa5c878983839c13ac3e653b3e9a647afc9..281fcaeade5b6f50929f5dc033f49abb20e11e87 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
@@ -18,12 +18,11 @@ import kotlin.random.Random
 class BufferViewManagerTest {
   @Test
   fun testEmpty() {
-    val state = BufferViewManagerState()
-    val actual = BufferViewManager(state = state).apply {
+    val actual = BufferViewManager().apply {
       update(emptyMap())
     }.state()
 
-    assertEquals(state, actual)
+    assertEquals(BufferViewManagerState(), actual)
   }
 
   @Test
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt
index acd04e80029e11016fea9a09066d1c373b64d1d0..7073f57adce4e9707f6abccfdd4b6c0f85351972 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt
@@ -31,12 +31,11 @@ import kotlin.random.Random
 class HighlightRuleManagerTest {
   @Test
   fun testEmpty() {
-    val state = HighlightRuleManagerState()
-    val actual = HighlightRuleManager(state = state).apply {
+    val actual = HighlightRuleManager().apply {
       update(emptyMap())
     }.state()
 
-    assertEquals(state, actual)
+    assertEquals(HighlightRuleManagerState(), actual)
   }
 
   @Test
@@ -160,8 +159,7 @@ class HighlightRuleManagerTest {
   }
 
   @Test
-  fun testNulLData() {
-    val random = Random(1337)
+  fun testNullData() {
     val actual = HighlightRuleManager(
       state = HighlightRuleManagerState()
     ).apply {
@@ -219,7 +217,8 @@ class HighlightRuleManagerTest {
               )
             ),
             QtType.QVariantMap
-          )
+          ),
+          "highlightNick" to qVariant(-2, QtType.Int)
         )
       )
     }.state()
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManagerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9f38d5d9de4441761cca2c958e28f48e0c207bfb
--- /dev/null
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/IgnoreListManagerTest.kt
@@ -0,0 +1,426 @@
+/*
+ * 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.syncables
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.rules.IgnoreRule
+import de.justjanne.libquassel.protocol.models.rules.IgnoreType
+import de.justjanne.libquassel.protocol.models.rules.ScopeType
+import de.justjanne.libquassel.protocol.models.rules.StrictnessType
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.syncables.state.IgnoreListManagerState
+import de.justjanne.libquassel.protocol.testutil.nextIgnoreRule
+import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.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 org.junit.jupiter.api.assertThrows
+import kotlin.random.Random
+
+class IgnoreListManagerTest {
+  @Test
+  fun testEmpty() {
+    val actual = IgnoreListManager().apply {
+      update(emptyMap())
+    }.state()
+
+    assertEquals(IgnoreListManagerState(), actual)
+  }
+
+  @Test
+  fun testInvalidData() {
+    val state = IgnoreListManagerState()
+    val actual = IgnoreListManager(state = state).apply {
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "ignoreRule" to qVariant<QStringList>(listOf(""), QtType.QStringList),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "isRegEx" to qVariant<QVariantList>(
+                  listOf(
+                    qVariant(false, QtType.Bool)
+                  ),
+                  QtType.QVariantList
+                ),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "strictness" to qVariant<QVariantList>(
+                  listOf(
+                    qVariant(StrictnessType.SoftStrictness.value, QtType.Int)
+                  ),
+                  QtType.QVariantList
+                ),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "isActive" to qVariant<QVariantList>(
+                  listOf(
+                    qVariant(false, QtType.Bool)
+                  ),
+                  QtType.QVariantList
+                ),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "scope" to qVariant<QVariantList>(
+                  listOf(
+                    qVariant(ScopeType.GlobalScope.value, QtType.Int)
+                  ),
+                  QtType.QVariantList
+                ),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+      assertThrows<IllegalArgumentException> {
+        update(
+          mapOf(
+            "IgnoreList" to qVariant<QVariantMap>(
+              mapOf(
+                "ignoreType" to qVariant<QVariantList>(emptyList(), QtType.QVariantList),
+                "scopeRule" to qVariant<QStringList>(listOf(""), QtType.QStringList),
+              ),
+              QtType.QVariantMap
+            )
+          )
+        )
+      }
+    }.state()
+
+    assertEquals(state, actual)
+  }
+
+  @Test
+  fun testNulLData() {
+    val actual = IgnoreListManager(
+      state = IgnoreListManagerState()
+    ).apply {
+      update(
+        mapOf(
+          "IgnoreList" to qVariant(
+            mapOf(
+              "ignoreType" to qVariant(
+                listOf(
+                  qVariant(-2, QtType.Int)
+                ),
+                QtType.QVariantList
+              ),
+              "ignoreRule" to qVariant(
+                listOf(null),
+                QtType.QStringList
+              ),
+              "isRegEx" to qVariant(
+                listOf(
+                  qVariant(false, QtType.Bool)
+                ),
+                QtType.QVariantList
+              ),
+              "strictness" to qVariant(
+                listOf(
+                  qVariant(-2, QtType.Int)
+                ),
+                QtType.QVariantList
+              ),
+              "isActive" to qVariant(
+                listOf(
+                  qVariant(false, QtType.Bool)
+                ),
+                QtType.QVariantList
+              ),
+              "scope" to qVariant(
+                listOf(
+                  qVariant(-2, QtType.Int)
+                ),
+                QtType.QVariantList
+              ),
+              "scopeRule" to qVariant(
+                listOf(
+                  null
+                ),
+                QtType.QStringList
+              )
+            ),
+            QtType.QVariantMap
+          )
+        )
+      )
+    }.state()
+
+    assertEquals(
+      IgnoreRule(
+        type = IgnoreType.SenderIgnore,
+        ignoreRule = "",
+        isRegEx = false,
+        strictness = StrictnessType.UnmatchedStrictness,
+        isEnabled = false,
+        scope = ScopeType.GlobalScope,
+        scopeRule = ""
+      ),
+      actual.rules.first()
+    )
+  }
+
+  @Test
+  fun testSerialization() {
+    val random = Random(1337)
+    val expected = IgnoreListManagerState(
+      rules = List(random.nextInt(20)) {
+        random.nextIgnoreRule()
+      }
+    )
+
+    val actual = IgnoreListManager(
+      state = IgnoreListManagerState()
+    ).apply {
+      update(IgnoreListManager(state = expected).toVariantMap())
+    }.state()
+
+    assertEquals(expected, actual)
+  }
+
+  @Nested
+  inner class Setters {
+    @Test
+    fun testRemoveIgnoreRule() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = value.state().rules.random(random)
+      assertTrue(value.contains(rule.ignoreRule))
+      assertNotEquals(-1, value.indexOf(rule.ignoreRule))
+      value.removeIgnoreListItem(rule.ignoreRule)
+      assertFalse(value.contains(rule.ignoreRule))
+      assertEquals(-1, value.indexOf(rule.ignoreRule))
+    }
+
+    @Test
+    fun testRemoveAll() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      assertFalse(value.isEmpty())
+      for (rule in value.state().rules) {
+        println(rule)
+        val index = value.state().indexOf(rule.ignoreRule)
+        println(index)
+        println(value.state().rules[index])
+        value.removeIgnoreListItem(rule.ignoreRule)
+      }
+      assertTrue(value.isEmpty())
+      assertEquals(0, value.count())
+    }
+
+    @Test
+    fun testToggleHighlightRule() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = value.state().rules.random(random)
+      assertTrue(value.contains(rule.ignoreRule))
+      assertNotEquals(-1, value.indexOf(rule.ignoreRule))
+      assertTrue(value.state().rules[value.indexOf(rule.ignoreRule)].isEnabled)
+      value.toggleIgnoreRule(rule.ignoreRule)
+      assertTrue(value.contains(rule.ignoreRule))
+      assertNotEquals(-1, value.indexOf(rule.ignoreRule))
+      assertFalse(value.state().rules[value.indexOf(rule.ignoreRule)].isEnabled)
+      value.toggleIgnoreRule(rule.ignoreRule)
+      assertTrue(value.contains(rule.ignoreRule))
+      assertNotEquals(-1, value.indexOf(rule.ignoreRule))
+      assertTrue(value.state().rules[value.indexOf(rule.ignoreRule)].isEnabled)
+    }
+
+    @Test
+    fun testAddExisting() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = value.state().rules.random(random)
+      val sizeBefore = value.count()
+      value.addIgnoreListItem(
+        type = rule.type.value,
+        ignoreRule = rule.ignoreRule,
+        isRegEx = rule.isRegEx,
+        strictness = rule.strictness.value,
+        scope = rule.scope.value,
+        scopeRule = rule.scopeRule,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore, value.count())
+    }
+
+    @Test
+    fun testAddNew() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = random.nextIgnoreRule()
+      val sizeBefore = value.count()
+      value.addIgnoreListItem(
+        type = rule.type.value,
+        ignoreRule = rule.ignoreRule,
+        isRegEx = rule.isRegEx,
+        strictness = rule.strictness.value,
+        scope = rule.scope.value,
+        scopeRule = rule.scopeRule,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore + 1, value.count())
+    }
+
+    @Test
+    fun testAddEdgeCase() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = random.nextIgnoreRule()
+      val sizeBefore = value.count()
+      value.addIgnoreListItem(
+        type = rule.type.value,
+        ignoreRule = null,
+        isRegEx = rule.isRegEx,
+        strictness = rule.strictness.value,
+        scope = rule.scope.value,
+        scopeRule = null,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore + 1, value.count())
+    }
+
+    @Test
+    fun testAddEdgeCaseUnchanged() {
+      val random = Random(1337)
+      val value = IgnoreListManager(
+        state = IgnoreListManagerState(
+          rules = List(random.nextInt(20)) {
+            random.nextIgnoreRule()
+          }
+        )
+      )
+
+      val rule = random.nextIgnoreRule()
+      val sizeBefore = value.count()
+      value.addIgnoreListItem(
+        type = -2,
+        ignoreRule = null,
+        isRegEx = rule.isRegEx,
+        strictness = rule.strictness.value,
+        scope = rule.scope.value,
+        scopeRule = null,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore, value.count())
+      value.addIgnoreListItem(
+        type = rule.type.value,
+        ignoreRule = null,
+        isRegEx = rule.isRegEx,
+        strictness = -2,
+        scope = rule.scope.value,
+        scopeRule = null,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore, value.count())
+      value.addIgnoreListItem(
+        type = rule.type.value,
+        ignoreRule = null,
+        isRegEx = rule.isRegEx,
+        strictness = rule.strictness.value,
+        scope = -2,
+        scopeRule = null,
+        isActive = rule.isEnabled
+      )
+      assertEquals(sizeBefore, value.count())
+    }
+  }
+}
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 fb4d1e7f7b12982fa43620a2f8e3b11c183ab5d7..7616b8cb60bbe6aad4a41a741033ede53078703e 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
@@ -10,10 +10,14 @@
 package de.justjanne.libquassel.protocol.syncables
 
 import de.justjanne.libquassel.protocol.models.ids.NetworkId
+import de.justjanne.libquassel.protocol.models.network.ChannelModes
 import de.justjanne.libquassel.protocol.syncables.state.IrcChannelState
+import de.justjanne.libquassel.protocol.testutil.MockSession
 import de.justjanne.libquassel.protocol.testutil.nextIrcChannel
+import de.justjanne.libquassel.protocol.testutil.nextNetwork
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Assertions.assertThrows
 import org.junit.jupiter.api.Nested
 import org.junit.jupiter.api.Test
 import kotlin.random.Random
@@ -82,4 +86,573 @@ class IrcChannelTest {
       assertEquals(true, channel.isEncrypted())
     }
   }
+
+  @Nested
+  inner class AddChannelMode {
+    @Test
+    fun noSession() {
+      val random = Random(1337)
+      val channel = IrcChannel(state = random.nextIrcChannel(NetworkId(random.nextInt())))
+
+      val channelModes = channel.state().channelModes
+      channel.addChannelMode('a', value = "*!*@*")
+      assertEquals(channelModes, channel.state().channelModes)
+    }
+
+    @Test
+    fun chanmodeUnknown() {
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(session, it.value.state())
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('e', value = "*!*@*")
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+    }
+
+    @Test
+    fun chanmodeA() {
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(session, it.value.state())
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('a', value = "*!*@*")
+      assertEquals(
+        mapOf(
+          'a' to setOf("*!*@*")
+        ),
+        channel.state().channelModes.a
+      )
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('a', value = "user!ident@host")
+      assertEquals(
+        mapOf(
+          'a' to setOf("*!*@*", "user!ident@host")
+        ),
+        channel.state().channelModes.a
+      )
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+
+      assertThrows(IllegalArgumentException::class.java) {
+        channel.addChannelMode('a', value = null)
+      }
+    }
+
+    @Test
+    fun chanmodeB() {
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(session, it.value.state())
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('b', value = "*!*@*")
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(
+        mapOf(
+          'b' to "*!*@*"
+        ),
+        channel.state().channelModes.b
+      )
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+
+      assertThrows(IllegalArgumentException::class.java) {
+        channel.addChannelMode('b', value = null)
+      }
+    }
+
+    @Test
+    fun chanmodeC() {
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(session, it.value.state())
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('c', value = "*!*@*")
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(
+        mapOf(
+          'c' to "*!*@*"
+        ),
+        channel.state().channelModes.c
+      )
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+
+      assertThrows(IllegalArgumentException::class.java) {
+        channel.addChannelMode('c', value = null)
+      }
+    }
+
+    @Test
+    fun chanmodeD() {
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(session, it.value.state())
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.supports())
+      println(network.channelModes())
+      println(network.session)
+      println(channel.session)
+
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+      channel.addChannelMode('d', value = "*!*@*")
+      assertEquals(emptyMap<Char, Set<String>>(), channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(setOf('d'), channel.state().channelModes.d)
+    }
+  }
+
+  @Nested
+  inner class RemoveChannelMode {
+    @Test
+    fun noSession() {
+
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2"),
+          'A' to setOf("A1", "A2")
+        ),
+        b = mapOf(
+          'b' to "b1",
+          'B' to "B1"
+        ),
+        c = mapOf(
+          'c' to "c1",
+          'C' to "C1"
+        ),
+        d = setOf('d', 'D')
+      )
+
+      val random = Random(1337)
+      val channel = IrcChannel(
+        state = random.nextIrcChannel(NetworkId(random.nextInt()))
+          .copy(channelModes = expected)
+      )
+
+      channel.removeChannelMode('a', value = "a1")
+      assertEquals(expected, channel.state().channelModes)
+    }
+
+    @Test
+    fun chanmodeUnknown() {
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2"),
+          'A' to setOf("A1", "A2")
+        ),
+        b = mapOf(
+          'b' to "b1",
+          'B' to "B1"
+        ),
+        c = mapOf(
+          'c' to "c1",
+          'C' to "C1"
+        ),
+        d = setOf('d', 'D')
+      )
+
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "a,b,c,d"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(
+                session,
+                it.value.state()
+                  .copy(channelModes = expected)
+              )
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.channelModes())
+
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('e', value = "*!*@*")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+    }
+
+    @Test
+    fun chanmodeA() {
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2")
+        ),
+        b = mapOf(
+          'b' to "b1"
+        ),
+        c = mapOf(
+          'c' to "c1"
+        ),
+        d = setOf('d')
+      )
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "aA,bB,cC,dD"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(
+                session,
+                it.value.state()
+                  .copy(channelModes = expected)
+              )
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.channelModes())
+
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('A', value = "a1")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('a', value = "a1")
+      assertEquals(
+        mapOf(
+          'a' to setOf("a2"),
+        ),
+        channel.state().channelModes.a
+      )
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('a', value = "a1")
+      assertEquals(
+        mapOf(
+          'a' to setOf("a2"),
+        ),
+        channel.state().channelModes.a
+      )
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+
+      assertThrows(IllegalArgumentException::class.java) {
+        channel.removeChannelMode('a', value = null)
+      }
+    }
+
+    @Test
+    fun chanmodeB() {
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2")
+        ),
+        b = mapOf(
+          'b' to "b1"
+        ),
+        c = mapOf(
+          'c' to "c1"
+        ),
+        d = setOf('d')
+      )
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "aA,bB,cC,dD"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(
+                session,
+                it.value.state()
+                  .copy(channelModes = expected)
+              )
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.channelModes())
+
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('B', value = "b1")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('b', value = "b1")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('b', value = "b2")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+    }
+
+    @Test
+    fun chanmodeC() {
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2")
+        ),
+        b = mapOf(
+          'b' to "b1"
+        ),
+        c = mapOf(
+          'c' to "c1"
+        ),
+        d = setOf('d')
+      )
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "aA,bB,cC,dD"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(
+                session,
+                it.value.state()
+                  .copy(channelModes = expected)
+              )
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.channelModes())
+
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('C', value = "c1")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('c', value = "c1")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('c', value = "c2")
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(emptyMap<Char, String>(), channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+    }
+
+    @Test
+    fun chanmodeD() {
+      val expected = ChannelModes(
+        a = mapOf(
+          'a' to setOf("a1", "a2")
+        ),
+        b = mapOf(
+          'b' to "b1"
+        ),
+        c = mapOf(
+          'c' to "c1"
+        ),
+        d = setOf('d')
+      )
+      val random = Random(1337)
+      val session = ChannelMockSession()
+      val network = Network(
+        session,
+        state = random.nextNetwork(NetworkId(random.nextInt())).run {
+          copy(
+            supports = mapOf(
+              "CHANMODES" to "aA,bB,cC,dD"
+            ),
+            ircChannels = ircChannels.mapValues {
+              IrcChannel(
+                session,
+                it.value.state()
+                  .copy(channelModes = expected)
+              )
+            },
+            ircUsers = ircUsers.mapValues {
+              IrcUser(session, it.value.state())
+            }
+          )
+        }
+      )
+      session.networks.add(network)
+      val channel = network.state().ircChannels.values.first()
+      println(network.channelModes())
+
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('D')
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(expected.d, channel.state().channelModes.d)
+      channel.removeChannelMode('d')
+      assertEquals(expected.a, channel.state().channelModes.a)
+      assertEquals(expected.b, channel.state().channelModes.b)
+      assertEquals(expected.c, channel.state().channelModes.c)
+      assertEquals(emptySet<Char>(), channel.state().channelModes.d)
+    }
+  }
+
+  class ChannelMockSession : MockSession() {
+    val networks = mutableListOf<Network>()
+    override fun network(id: NetworkId) = networks.find { it.networkId() == id }
+  }
 }
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
index 4575d537f3ed7f6e657039a15a10d0895a9620dc..fb29e95207f0ce659a64ebb48108927efbd4e654 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt
@@ -10,7 +10,7 @@
 package de.justjanne.libquassel.protocol.testutil
 
 import de.justjanne.bitflags.of
-import de.justjanne.libquassel.protocol.models.flags.BufferActivity
+import de.justjanne.libquassel.protocol.models.BufferActivity
 import de.justjanne.libquassel.protocol.models.flags.BufferType
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.IdentityId
@@ -168,16 +168,16 @@ fun Random.nextBufferViewConfig(
       nextEnum()
     }
   ),
-  minimumActivity = BufferActivity.of(nextEnum<BufferActivity>()),
+  minimumActivity = nextEnum<BufferActivity>(),
   showSearch = nextBoolean(),
-  buffers = List(nextInt(20)) {
-    BufferId(nextInt())
-  },
-  removedBuffers = List(nextInt(20)) {
-    BufferId(nextInt())
+  buffers = List(nextInt(5, 20)) {
+    BufferId(nextInt(0, 33))
+  }.toSet().toList().shuffled(),
+  removedBuffers = List(nextInt(5, 20)) {
+    BufferId(nextInt(34, 66))
   }.toSet(),
-  temporarilyRemovedBuffers = List(nextInt(20)) {
-    BufferId(nextInt())
+  hiddenBuffers = List(nextInt(5, 20)) {
+    BufferId(nextInt(67, 100))
   }.toSet()
 )
 
diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
index ea75256ca4ebb2581101cec282481fddc64083aa..84e203a80fc5c025edf49c217fbf4d6a2b31caf4 100644
--- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
+++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/util/collections/MoveTest.kt
@@ -51,4 +51,13 @@ class MoveTest {
       )
     }
   }
+
+  @Test
+  fun movesCorrectly() {
+    val data = listOf(1, 2, 3, 4, 5, 7).shuffled()
+    assertEquals(
+      listOf('a', 'c', 'd', 'e', 'b', 'f'),
+      listOf('a', 'b', 'c', 'd', 'e', 'f').move('b', 4)
+    )
+  }
 }