diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Protocol.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Protocol.kt
index fabfb3b4dff0100e15b6ca8836fe9e2cd71236d3..788529757a9777df7c389e27a489dc725061dec9 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/Protocol.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Protocol.kt
@@ -19,15 +19,19 @@
 
 package de.kuschku.libquassel.protocol
 
-enum class Protocol(private val value: Byte) {
-  Legacy(0x01),
-  Datastream(0x02);
+enum class Protocol(private val value: UByte) {
+  Legacy(0x01u),
+  Datastream(0x02u);
 
-  fun toDouble(): Double = value.toDouble()
-  fun toFloat(): Float = value.toFloat()
-  fun toLong(): Long = value.toLong()
-  fun toInt(): Int = value.toInt()
-  fun toChar(): Char = value.toChar()
-  fun toShort(): Short = value.toShort()
-  fun toByte(): Byte = value
+  fun toByte() = value.toByte()
+  fun toChar() = value.toInt().toChar()
+  fun toDouble() = value.toInt().toDouble()
+  fun toFloat() = value.toInt().toFloat()
+  fun toInt() = value.toInt()
+  fun toLong() = value.toLong()
+  fun toShort() = value.toShort()
+  fun toUByte() = value.toUByte()
+  fun toUInt() = value.toUInt()
+  fun toULong() = value.toULong()
+  fun toUShort() = value.toUShort()
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
index 9cba2781461e382282d6c6352467f5195026acac..6cdda9c1dae3bbb0068c485e6e964f0d4dd45f8c 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializer.kt
@@ -29,15 +29,15 @@ object ProtocolInfoSerializer : Serializer<ProtocolInfo> {
   override fun serialize(buffer: ChainedByteBuffer, data: ProtocolInfo,
                          features: QuasselFeatures) {
     UByteSerializer.serialize(buffer, data.flags.toUByte(), features)
-    ShortSerializer.serialize(buffer, data.data, features)
-    ByteSerializer.serialize(buffer, data.version, features)
+    UShortSerializer.serialize(buffer, data.data, features)
+    UByteSerializer.serialize(buffer, data.version, features)
   }
 
   override fun deserialize(buffer: ByteBuffer, features: QuasselFeatures): ProtocolInfo {
     return ProtocolInfo(
       Protocol_Features.of(UByteSerializer.deserialize(buffer, features).toUInt()),
-      ShortSerializer.deserialize(buffer, features),
-      ByteSerializer.deserialize(buffer, features)
+      UShortSerializer.deserialize(buffer, features),
+      UByteSerializer.deserialize(buffer, features)
     )
   }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolInfo.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolInfo.kt
index 1c1486be5146babde2a1c9426525fd34d8791c53..684713ceec6f70cec8f6d377682b1caa1cef2b2f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolInfo.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolInfo.kt
@@ -21,4 +21,4 @@ package de.kuschku.libquassel.quassel
 
 import de.kuschku.libquassel.protocol.Protocol_Features
 
-data class ProtocolInfo(val flags: Protocol_Features, val data: Short, val version: Byte)
+data class ProtocolInfo(val flags: Protocol_Features, val data: UShort, val version: UByte)
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
index 4457839025bc95dcb7dc88e67ed02112ecd39184..1f2e5cf05a6616e4fd23e7f857e42378703b0544 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/AliasManager.kt
@@ -74,22 +74,6 @@ class AliasManager constructor(
 
   fun contains(name: String?) = _aliases.map(Alias::name).contains(name)
 
-  fun defaults() = listOf(
-    Alias("j", "/join $0"),
-    Alias("ns", "/msg nickserv $0"),
-    Alias("nickserv", "/msg nickserv $0"),
-    Alias("cs", "/msg chanserv $0"),
-    Alias("chanserv", "/msg chanserv $0"),
-    Alias("hs", "/msg hostserv $0"),
-    Alias("hostserv", "/msg hostserv $0"),
-    Alias("wii", "/whois $0 $0"),
-    Alias("back", "/quote away"),
-
-    // let's add aliases for scripts that only run on linux
-    Alias("inxi", "/exec inxi $0"),
-    Alias("sysinfo", "/exec inxi -d")
-  )
-
   fun aliasList() = _aliases
 
   fun setAliasList(list: List<Alias>) {
@@ -102,6 +86,12 @@ class AliasManager constructor(
     it.fromVariantMap(toVariantMap())
   }
 
+  fun processInput(info: BufferInfo, message: String): List<IAliasManager.Command> {
+    val result = mutableListOf<IAliasManager.Command>()
+    processInput(info, message, result)
+    return result
+  }
+
   fun processInput(info: BufferInfo, message: String,
                    previousCommands: MutableList<IAliasManager.Command>) {
     var msg = message
@@ -233,4 +223,22 @@ class AliasManager constructor(
   override fun toString(): String {
     return "AliasManager(_aliases=$_aliases)"
   }
+
+  companion object {
+    fun defaults() = listOf(
+      Alias("j", "/join $0"),
+      Alias("ns", "/msg nickserv $0"),
+      Alias("nickserv", "/msg nickserv $0"),
+      Alias("cs", "/msg chanserv $0"),
+      Alias("chanserv", "/msg chanserv $0"),
+      Alias("hs", "/msg hostserv $0"),
+      Alias("hostserv", "/msg hostserv $0"),
+      Alias("wii", "/whois $0 $0"),
+      Alias("back", "/quote away"),
+
+      // let's add aliases for scripts that only run on linux
+      Alias("inxi", "/exec inxi $0"),
+      Alias("sysinfo", "/exec inxi -d")
+    )
+  }
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
index 0730f568672750c1343159521fda58753d377b42..b8d2066a56bb7bdd506c6501217110ff58e9259e 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferSyncer.kt
@@ -91,11 +91,23 @@ class BufferSyncer constructor(
     initSetMarkerLines(properties["MarkerLines"].valueOr(::emptyList))
   }
 
+  fun copy() = BufferSyncer(session).also {
+    it.fromVariantMap(toVariantMap())
+  }
+
+  fun isEqual(other: BufferSyncer) =
+    _bufferInfos == other._bufferInfos &&
+    _lastSeenMsg == other._lastSeenMsg &&
+    _markerLines == other._markerLines &&
+    _bufferActivities == other._bufferActivities &&
+    _highlightCounts == other._highlightCounts
+
+
   override fun initActivities(): QVariantList {
     val list: MutableList<QVariant_> = mutableListOf()
     for ((key, value) in _bufferActivities) {
       list.add(QVariant.of(key, QType.BufferId))
-      list.add(QVariant.of(value, Type.Int))
+      list.add(QVariant.of(value.toInt(), Type.Int))
     }
     return list
   }
@@ -111,7 +123,7 @@ class BufferSyncer constructor(
 
   override fun initLastSeenMsg(): QVariantList {
     val list: MutableList<QVariant_> = mutableListOf()
-    for ((key, value) in _bufferActivities) {
+    for ((key, value) in _lastSeenMsg) {
       list.add(QVariant.of(key, QType.BufferId))
       list.add(QVariant.of(value, QType.MsgId))
     }
@@ -120,7 +132,7 @@ class BufferSyncer constructor(
 
   override fun initMarkerLines(): QVariantList {
     val list: MutableList<QVariant_> = mutableListOf()
-    for ((key, value) in _bufferActivities) {
+    for ((key, value) in _markerLines) {
       list.add(QVariant.of(key, QType.BufferId))
       list.add(QVariant.of(value, QType.MsgId))
     }
@@ -128,44 +140,78 @@ class BufferSyncer constructor(
   }
 
   override fun initSetActivities(data: QVariantList) {
-    (0 until data.size step 2).map {
-      data[it].value(BufferId(0)) to data[it + 1].value(0)
-    }.forEach { (buffer, activity) ->
+    setActivities((0 until data.size step 2).map {
+      Pair(
+        data[it].value(BufferId(0)),
+        Message_Type.of(data[it + 1].value(0))
+      )
+    })
+  }
+
+  fun setActivities(data: List<Pair<BufferId, Message_Types>>) {
+    for ((buffer, activity) in data) {
       setBufferActivity(buffer, activity)
     }
     live_bufferActivities.onNext(Unit)
   }
 
   override fun initSetHighlightCounts(data: QVariantList) {
-    (0 until data.size step 2).map {
-      data[it].value(BufferId(0)) to data[it + 1].value(0)
-    }.forEach { (buffer, count) ->
+    setHighlightCounts((0 until data.size step 2).map {
+      Pair(
+        data[it].value(BufferId(0)),
+        data[it + 1].value(0)
+      )
+    })
+  }
+
+  fun setHighlightCounts(data: List<Pair<BufferId, Int>>) {
+    for ((buffer, count) in data) {
       setHighlightCount(buffer, count)
     }
     live_highlightCounts.onNext(Unit)
   }
 
   override fun initSetLastSeenMsg(data: QVariantList) {
-    (0 until data.size step 2).map {
-      data[it].value(BufferId(0)) to data[it + 1].value(MsgId(0L))
-    }.forEach { (buffer, msgId) ->
+    setLastSeenMsg((0 until data.size step 2).map {
+      Pair(
+        data[it].value(BufferId(0)),
+        data[it + 1].value(MsgId(0L))
+      )
+    })
+  }
+
+  fun setLastSeenMsg(data: List<Pair<BufferId, MsgId>>) {
+    for ((buffer, msgId) in data) {
       setLastSeenMsg(buffer, msgId)
     }
     live_lastSeenMsg.onNext(Unit)
   }
 
   override fun initSetMarkerLines(data: QVariantList) {
-    (0 until data.size step 2).map {
-      data[it].value(BufferId(0)) to data[it + 1].value(MsgId(0L))
-    }.forEach { (buffer, msgId) ->
+    setMarkerLines((0 until data.size step 2).map {
+      Pair(
+        data[it].value(BufferId(0)),
+        data[it + 1].value(MsgId(0L))
+      )
+    })
+  }
+
+  fun setMarkerLines(data: List<Pair<BufferId, MsgId>>) {
+    for ((buffer, msgId) in data) {
       setMarkerLine(buffer, msgId)
     }
     live_markerLines.onNext(Unit)
   }
 
   fun initSetBufferInfos(infos: QVariantList?) {
+    setBufferInfos(infos?.mapNotNull { it.value<BufferInfo>() }.orEmpty())
+  }
+
+  fun setBufferInfos(infos: List<BufferInfo>) {
     _bufferInfos.clear()
-    infos?.mapNotNull { it.value<BufferInfo>() }?.forEach { _bufferInfos[it.bufferId] = it }
+    for (info in infos) {
+      _bufferInfos[info.bufferId] = info
+    }
     live_bufferInfos.onNext(Unit)
   }
 
@@ -226,16 +272,19 @@ class BufferSyncer constructor(
   }
 
   override fun setBufferActivity(buffer: BufferId, activity: Int) {
-    val flags = Message_Types.of<Message_Type>(activity)
-    super.setBufferActivity(buffer, activity)
-    if (flags hasFlag Message_Type.Plain ||
-        flags hasFlag Message_Type.Notice ||
-        flags hasFlag Message_Type.Action) {
+    setBufferActivity(buffer, Message_Type.of(activity))
+  }
+
+  fun setBufferActivity(buffer: BufferId, activity: Message_Types) {
+    super.setBufferActivity(buffer, activity.toInt())
+    if (activity hasFlag Message_Type.Plain ||
+        activity hasFlag Message_Type.Notice ||
+        activity hasFlag Message_Type.Action) {
       bufferInfo(buffer)?.let {
         session.bufferViewManager.handleBuffer(it, this, true)
       }
     }
-    _bufferActivities[buffer] = flags
+    _bufferActivities[buffer] = activity
     live_bufferActivities.onNext(Unit)
   }
 
@@ -272,6 +321,10 @@ class BufferSyncer constructor(
     groupId: Int? = null
   ) = all(bufferName, bufferId, networkId, type, groupId).firstOrNull()
 
+  override fun toString(): String {
+    return "BufferSyncer(_lastSeenMsg=$_lastSeenMsg, _markerLines=$_markerLines, _bufferActivities=$_bufferActivities, _highlightCounts=$_highlightCounts, _bufferInfos=$_bufferInfos)"
+  }
+
   private val _lastSeenMsg: MutableMap<BufferId, MsgId> = mutableMapOf()
   private val live_lastSeenMsg = BehaviorSubject.createDefault(Unit)
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
index 179c60127075fc2c90ddf0b07f68e10797ffba38..84312e5ceeac65720415aa5a9762864862286b3c 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
@@ -37,6 +37,13 @@ class BufferViewManager constructor(
     initSetBufferViewIds(properties["BufferViewIds"].valueOr(::emptyList))
   }
 
+  fun copy() = BufferViewManager(proxy).also {
+    it.fromVariantMap(toVariantMap())
+  }
+
+  fun isEqual(other: BufferViewManager) =
+    _bufferViewConfigs.keys == other._bufferViewConfigs.keys
+
   override fun initBufferViewIds(): QVariantList = _bufferViewConfigs.keys.map {
     QVariant.of(it, Type.Int)
   }
@@ -48,9 +55,13 @@ class BufferViewManager constructor(
   fun liveBufferViewConfigs(): Observable<Set<Int>> = live_bufferViewConfigs
 
   override fun initSetBufferViewIds(bufferViewIds: QVariantList) {
-    bufferViewIds
-      .mapNotNull { it.value<Int>() }
-      .forEach { addBufferViewConfig(it) }
+    setBufferViewIds(bufferViewIds.mapNotNull { it.value<Int>() })
+  }
+
+  fun setBufferViewIds(ids: List<Int>) {
+    for (id in ids) {
+      addBufferViewConfig(id)
+    }
   }
 
   override fun addBufferViewConfig(config: BufferViewConfig) {
@@ -91,4 +102,10 @@ class BufferViewManager constructor(
   override fun deinit() {
     _bufferViewConfigs.values.map(BufferViewConfig::deinit)
   }
+
+  override fun toString(): String {
+    return "BufferViewManager(_bufferViewConfigs=${_bufferViewConfigs.keys})"
+  }
+
+
 }
diff --git a/lib/src/test/java/de/kuschku/libquassel/integration/AliasManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/integration/AliasManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5aeabd04c4d7166ff82467271386ae5c113f7
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/integration/AliasManagerTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.integration
+
+import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
+import de.kuschku.libquassel.util.TestSession
+import de.kuschku.libquassel.util.setupTestSession
+import de.kuschku.libquassel.util.with
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+class AliasManagerTest {
+  lateinit var session: TestSession
+  lateinit var channelBuffer: BufferInfo
+  lateinit var queryBuffer: BufferInfo
+
+  @Before
+  fun setUp() {
+    session = setupTestSession()
+    session.aliasManager.setAliasList(listOf(
+      IAliasManager.Alias(
+        "userexpansion",
+        "$1 $1:account $1:hostname $1:identd $1:ident"
+      ),
+      IAliasManager.Alias(
+        "channelexpansion",
+        "\$channel"
+      ),
+      IAliasManager.Alias(
+        "rangeexpansion",
+        "1 \"\$1\" 2 \"\$2\" 3..4 \"\$3..4\" 3.. \"\$3..\""
+      )
+    ))
+
+    channelBuffer = session.bufferSyncer.find(
+      bufferName = "#quassel-test",
+      networkId = NetworkId(1)
+    )!!
+    assert(channelBuffer.type == Buffer_Type.of(Buffer_Type.ChannelBuffer))
+
+    queryBuffer = session.bufferSyncer.find(
+      bufferName = "digitalcircuit",
+      networkId = NetworkId(1)
+    )!!
+    assert(queryBuffer.type == Buffer_Type.of(Buffer_Type.QueryBuffer))
+  }
+
+  // Test with user where identd works
+  @Test
+  fun userExpansionWithIdentd() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        channelBuffer,
+        "justJanne justJanne kuschku.de kuschku kuschku"
+      )),
+      aliasManager.processInput(
+        channelBuffer,
+        "/userexpansion justJanne"
+      )
+    )
+  }
+
+  // Test with user where identd doesn’t work
+  @Test
+  fun userExpansionNoIdentd() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        channelBuffer,
+        "digitalcircuit digitalcircuit 2605:6000:1518:830d:ec4:7aff:fe6b:c6b0 * ~quassel"
+      )),
+      aliasManager.processInput(
+        channelBuffer,
+        "/userexpansion digitalcircuit"
+      )
+    )
+  }
+
+  // Test with user that isn’t even in channel
+  @Test
+  fun userExpansionUnknownUser() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        channelBuffer,
+        "ChanServ * * * *"
+      )),
+      aliasManager.processInput(
+        channelBuffer,
+        "/userexpansion ChanServ"
+      )
+    )
+  }
+
+  // Test in query
+  @Test
+  fun userExpansionQuery() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        queryBuffer,
+        "digitalcircuit digitalcircuit 2605:6000:1518:830d:ec4:7aff:fe6b:c6b0 * ~quassel"
+      )),
+      aliasManager.processInput(
+        queryBuffer,
+        "/userexpansion digitalcircuit"
+      )
+    )
+  }
+
+  @Test
+  fun channelExpansionChannel() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        channelBuffer,
+        "#quassel-test"
+      )),
+      aliasManager.processInput(
+        channelBuffer,
+        "/channelexpansion"
+      )
+    )
+  }
+
+  @Test
+  fun channelExpansionQuery() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        queryBuffer,
+        "digitalcircuit"
+      )),
+      aliasManager.processInput(
+        queryBuffer,
+        "/channelexpansion"
+      )
+    )
+  }
+
+  @Test
+  fun rangeExpansion() = session.with {
+    assertEquals(
+      listOf(IAliasManager.Command(
+        queryBuffer,
+        "1 \"a\" 2 \"b\" 3..4 \"c d\" 3.. \"c d e f\""
+      )),
+      aliasManager.processInput(
+        queryBuffer,
+        "/rangeexpansion a b c d e f"
+      )
+    )
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/IntegrationTest.kt b/lib/src/test/java/de/kuschku/libquassel/integration/SampleIntegrationTest.kt
similarity index 95%
rename from lib/src/test/java/de/kuschku/libquassel/IntegrationTest.kt
rename to lib/src/test/java/de/kuschku/libquassel/integration/SampleIntegrationTest.kt
index e0690bc2e7854e7fae95bcdae70ff40d4a86b29c..0cd4aee89e87d901b1a5d02b9fd746640bbcd6c0 100644
--- a/lib/src/test/java/de/kuschku/libquassel/IntegrationTest.kt
+++ b/lib/src/test/java/de/kuschku/libquassel/integration/SampleIntegrationTest.kt
@@ -17,7 +17,7 @@
  * with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.libquassel
+package de.kuschku.libquassel.integration
 
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.protocol.QType
@@ -26,7 +26,7 @@ import de.kuschku.libquassel.protocol.Type
 import de.kuschku.libquassel.util.withTestSession
 import org.junit.Test
 
-class IntegrationTest {
+class SampleIntegrationTest {
   @Test
   fun test() = withTestSession {
     ensure {
diff --git a/lib/src/test/java/de/kuschku/libquassel/integration/SignedIdNameTests.kt b/lib/src/test/java/de/kuschku/libquassel/integration/SignedIdNameTests.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3880b1ec5501d8a6e54eed1876c218069613667d
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/integration/SignedIdNameTests.kt
@@ -0,0 +1,72 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.integration
+
+import de.kuschku.libquassel.protocol.IdentityId
+import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.util.withTestSession
+import org.junit.Test
+
+/*
+ * When implementing SignedIds properly for the first time, we noticed that they were used in
+ * objectNames directly, leading e.g. IrcChannel’s renameObject("${network().networkId()}/${name()}")
+ * to return "NetworkId(4)/justJanne" instead of the "4/justJanne" that it used to.
+ *
+ * This test exists to prevent this regression from reoccuring.
+ */
+class SignedIdNameTests {
+  @Test
+  fun testNetworkName() = withTestSession {
+    ensure {
+      addNetwork(buildNetwork(NetworkId(2)), initialize = true)
+    }.does {
+      requestInit("Network", "2")
+    }
+  }
+
+  @Test
+  fun testIdentityName() = withTestSession {
+    ensure {
+      addIdentity(buildIdentity(IdentityId(2)), initialize = true)
+    }.does {
+      requestInit("Identity", "2")
+    }
+  }
+
+  @Test
+  fun testIrcUserName() = withTestSession {
+    ensure {
+      val network = network(NetworkId(1))!!
+      network.addIrcUser("testuser")
+    }.does {
+      requestInit("IrcUser", "1/testuser")
+    }
+  }
+
+  @Test
+  fun testIrcChannelName() = withTestSession {
+    ensure {
+      val network = network(NetworkId(1))!!
+      network.addIrcChannel("#testchannel")
+    }.does {
+      requestInit("IrcChannel", "1/#testchannel")
+    }
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b3f6df414612a37d50314f254862c286c969dcf1
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/HostAddressSerializerTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.util.deserialize
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import java.net.InetAddress
+
+class HostAddressSerializerTest {
+  @Test
+  fun testIpv4() {
+    val address = InetAddress.getByName("176.9.136.3")
+    assertEquals(address, roundTrip(HostAddressSerializer, address))
+    // @formatter:off
+    assertEquals(address, deserialize(HostAddressSerializer, byteArrayOf(0, -80, 9, -120, 3)))
+    // @formatter:on
+  }
+
+  @Test
+  fun testIpv6() {
+    val address = InetAddress.getByName("[2a01:4f8:160:1012::2]")
+    assertEquals(address, roundTrip(HostAddressSerializer, address))
+    // @formatter:off
+    assertEquals(address, deserialize(HostAddressSerializer, byteArrayOf(1, 42, 1, 4, -8, 1, 96, 16, 18, 0, 0, 0, 0, 0, 0, 0, 2)))
+    // @formatter:on
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializerTest.kt b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5d3c77f84bd5ef485a5e07c5bc00453063d3b339
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/protocol/primitive/serializer/ProtocolInfoSerializerTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.protocol.primitive.serializer
+
+import de.kuschku.libquassel.protocol.Protocol
+import de.kuschku.libquassel.protocol.Protocol_Feature
+import de.kuschku.libquassel.quassel.ProtocolInfo
+import de.kuschku.libquassel.util.deserialize
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ProtocolInfoSerializerTest {
+  @Test
+  fun testNone() {
+    val data = ProtocolInfo(
+      flags = Protocol_Feature.of(),
+      data = 0u,
+      version = 0u
+    )
+    assertEquals(data, roundTrip(ProtocolInfoSerializer, data))
+    // @formatter:off
+    assertEquals(data, deserialize(ProtocolInfoSerializer, byteArrayOf(0, 0, 0, 0)))
+    // @formatter:on
+  }
+
+  @Test
+  fun testUsual() {
+    val data = ProtocolInfo(
+      flags = Protocol_Feature.of(
+        Protocol_Feature.TLS,
+        Protocol_Feature.Compression
+      ),
+      data = 0u,
+      version = Protocol.Datastream.toUByte()
+    )
+    assertEquals(data, roundTrip(ProtocolInfoSerializer, data))
+    // @formatter:off
+    assertEquals(data, deserialize(ProtocolInfoSerializer, byteArrayOf(3, 0, 0, 2)))
+    // @formatter:on
+  }
+
+  @Test
+  fun testExtreme() {
+    val data = ProtocolInfo(
+      flags = Protocol_Feature.of(
+        Protocol_Feature.TLS,
+        Protocol_Feature.Compression
+      ),
+      data = 0xffffu,
+      version = 0xffu
+    )
+    assertEquals(data, roundTrip(ProtocolInfoSerializer, data))
+    // @formatter:off
+    assertEquals(data, deserialize(ProtocolInfoSerializer, byteArrayOf(3, -1, -1, -1)))
+    // @formatter:on
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt
index 1be52a9e57a51ececae99965f676242416317c9b..89b9dcf7a5d400b4b4b0881360aa0982044f6d57 100644
--- a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/AliasManagerTest.kt
@@ -19,23 +19,16 @@
 
 package de.kuschku.libquassel.quassel.syncables
 
-import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.Buffer_Types
-import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
-import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
 import de.kuschku.libquassel.session.SignalProxy
 import de.kuschku.libquassel.util.roundTrip
-import org.junit.Assert.assertEquals
 import org.junit.Test
 
 class AliasManagerTest {
   @Test
   fun testSerialization() {
     val original = AliasManager(SignalProxy.NULL)
-    original.setAliasList(original.defaults())
+    original.setAliasList(AliasManager.defaults())
 
     val copy = original.copy()
     copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
@@ -48,7 +41,7 @@ class AliasManagerTest {
   @Test
   fun testCopy() {
     val original = AliasManager(SignalProxy.NULL)
-    original.setAliasList(original.defaults())
+    original.setAliasList(AliasManager.defaults())
 
     val copy = original.copy()
     copy.fromVariantMap(original.toVariantMap())
@@ -57,60 +50,4 @@ class AliasManagerTest {
       System.err.println("Copy:\n$copy")
     }
   }
-
-  @Test
-  fun testExpansion() {
-    fun testExpansion(aliases: List<IAliasManager.Alias>, original: String,
-                      expanded: List<String>) {
-      val manager = AliasManager(SignalProxy.NULL)
-      manager.setAliasList(manager.defaults() + aliases)
-
-      val bufferInfo = BufferInfo(
-        bufferId = BufferId(-1),
-        networkId = NetworkId(-1),
-        type = Buffer_Types.of(Buffer_Type.StatusBuffer),
-        bufferName = "#quassel-test",
-        groupId = -1
-      )
-
-      val previousCommands = mutableListOf<IAliasManager.Command>()
-      manager.processInput(
-        info = bufferInfo,
-        message = original,
-        previousCommands = previousCommands
-      )
-
-      assertEquals(previousCommands, expanded.map {
-        IAliasManager.Command(bufferInfo, it)
-      })
-    }
-
-    testExpansion(
-      listOf(
-        IAliasManager.Alias(
-          name = "d",
-          expansion = "/say first \"\$1\" second \"\$2\" some \"\$3..4\" more \"\$3..\""
-        )
-      ),
-      "/d a b c d e f",
-      listOf(
-        "/say first \"a\" second \"b\" some \"c d\" more \"c d e f\""
-      )
-    )
-
-    testExpansion(
-      listOf(
-        IAliasManager.Alias(
-          name = "test",
-          expansion = "Test $1; Test $2; Test All $0"
-        )
-      ),
-      "/test 1 2 3",
-      listOf(
-        "Test 1",
-        "Test 2",
-        "Test All 1 2 3"
-      )
-    )
-  }
 }
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferSyncerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferSyncerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..294def8d537d80cb15b0d8d22cdc26f2ba11bf0b
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferSyncerTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.libquassel.protocol.MsgId
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.ISession
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Test
+
+class BufferSyncerTest {
+  @Test
+  fun testSerialization() {
+    val original = BufferSyncer(ISession.NULL)
+    original.setLastSeenMsg(listOf(
+      Pair(BufferId(1), MsgId(16)),
+      Pair(BufferId(2), MsgId(17)),
+      Pair(BufferId(3), MsgId(18)),
+      Pair(BufferId(4), MsgId(19))
+    ))
+    original.setMarkerLines(listOf(
+      Pair(BufferId(1), MsgId(26)),
+      Pair(BufferId(2), MsgId(27)),
+      Pair(BufferId(3), MsgId(28)),
+      Pair(BufferId(4), MsgId(29))
+    ))
+    original.setActivities(listOf(
+      Pair(BufferId(1), Message_Type.of(Message_Type.Plain)),
+      Pair(BufferId(2), Message_Type.of(Message_Type.Notice)),
+      Pair(BufferId(3), Message_Type.of(Message_Type.Action)),
+      Pair(BufferId(4), Message_Type.of(Message_Type.Error))
+    ))
+    original.setHighlightCounts(listOf(
+      Pair(BufferId(1), 36),
+      Pair(BufferId(2), 37),
+      Pair(BufferId(3), 38),
+      Pair(BufferId(4), 39)
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    assert(original.isEqual(copy)) {
+      System.err.println("Original:\n$original")
+      System.err.println("Copy:\n$copy")
+    }
+  }
+
+  @Test
+  fun testCopy() {
+    val original = BufferSyncer(ISession.NULL)
+    original.setLastSeenMsg(listOf(
+      Pair(BufferId(1), MsgId(16)),
+      Pair(BufferId(2), MsgId(17)),
+      Pair(BufferId(3), MsgId(18)),
+      Pair(BufferId(4), MsgId(19))
+    ))
+    original.setMarkerLines(listOf(
+      Pair(BufferId(1), MsgId(26)),
+      Pair(BufferId(2), MsgId(27)),
+      Pair(BufferId(3), MsgId(28)),
+      Pair(BufferId(4), MsgId(29))
+    ))
+    original.setActivities(listOf(
+      Pair(BufferId(1), Message_Type.of(Message_Type.Plain)),
+      Pair(BufferId(2), Message_Type.of(Message_Type.Notice)),
+      Pair(BufferId(3), Message_Type.of(Message_Type.Action)),
+      Pair(BufferId(4), Message_Type.of(Message_Type.Error))
+    ))
+    original.setHighlightCounts(listOf(
+      Pair(BufferId(1), 36),
+      Pair(BufferId(2), 37),
+      Pair(BufferId(3), 38),
+      Pair(BufferId(4), 39)
+    ))
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    assert(original.isEqual(copy)) {
+      System.err.println("Original:\n$original")
+      System.err.println("Copy:\n$copy")
+    }
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewManagerTest.kt b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..240341760daf5c5ef2d034d28d18103e18b38292
--- /dev/null
+++ b/lib/src/test/java/de/kuschku/libquassel/quassel/syncables/BufferViewManagerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.libquassel.quassel.syncables
+
+import de.kuschku.libquassel.protocol.primitive.serializer.VariantMapSerializer
+import de.kuschku.libquassel.session.SignalProxy
+import de.kuschku.libquassel.util.roundTrip
+import org.junit.Test
+
+class BufferViewManagerTest {
+  @Test
+  fun testSerialization() {
+    val original = BufferViewManager(SignalProxy.NULL)
+    original.setBufferViewIds(listOf(-1, 0, 9999, Int.MIN_VALUE, Int.MAX_VALUE))
+
+    val copy = original.copy()
+    copy.fromVariantMap(roundTrip(VariantMapSerializer, original.toVariantMap()))
+    assert(original.isEqual(copy)) {
+      System.err.println("Original:\n$original")
+      System.err.println("Copy:\n$copy")
+    }
+  }
+
+  @Test
+  fun testCopy() {
+    val original = BufferViewManager(SignalProxy.NULL)
+    original.setBufferViewIds(listOf(-1, 0, 9999, Int.MIN_VALUE, Int.MAX_VALUE))
+
+    val copy = original.copy()
+    copy.fromVariantMap(original.toVariantMap())
+    assert(original.isEqual(copy)) {
+      System.err.println("Original:\n$original")
+      System.err.println("Copy:\n$copy")
+    }
+  }
+}
diff --git a/lib/src/test/java/de/kuschku/libquassel/util/SetupTests.kt b/lib/src/test/java/de/kuschku/libquassel/util/SetupTests.kt
index 2c46893b28183afdc98a9d427dab20de131ca23c..3966b45fe1dcf028494f5e31fd285404047730db 100644
--- a/lib/src/test/java/de/kuschku/libquassel/util/SetupTests.kt
+++ b/lib/src/test/java/de/kuschku/libquassel/util/SetupTests.kt
@@ -19,16 +19,21 @@
 
 package de.kuschku.libquassel.util
 
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.Buffer_Type
 import de.kuschku.libquassel.protocol.IdentityId
 import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.AliasManager
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 
+fun TestSession.with(f: TestSession.() -> Unit) = f.invoke(this)
+
 fun withTestSession(f: TestSession.() -> Unit) = f.invoke(setupTestSession())
 
 fun setupTestSession() = TestSession().provideTestData {
   identities = listOf(
-    buildIdentity {
-      setId(IdentityId(1))
+    buildIdentity(IdentityId(1)) {
       setIdentityName("Default Identity")
       setRealName("Janne Mareike Koschinski <janne@kuschku.de>")
       setNicks(listOf(
@@ -40,6 +45,7 @@ fun setupTestSession() = TestSession().provideTestData {
       setIdent("justJanne")
     }
   )
+
   networks = listOf(
     buildNetwork(NetworkId(1)) {
       setNetworkName("FreeNode")
@@ -135,4 +141,41 @@ fun setupTestSession() = TestSession().provideTestData {
       }
     }
   )
+
+  buffers = listOf(
+    TestSession.BufferTestData(
+      bufferInfo = BufferInfo(
+        bufferId = BufferId(1),
+        networkId = NetworkId(1),
+        bufferName = "FreeNode",
+        type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+      )
+    ),
+    TestSession.BufferTestData(
+      bufferInfo = BufferInfo(
+        bufferId = BufferId(2),
+        networkId = NetworkId(1),
+        bufferName = "#quassel-test",
+        type = Buffer_Type.of(Buffer_Type.ChannelBuffer)
+      )
+    ),
+    TestSession.BufferTestData(
+      bufferInfo = BufferInfo(
+        bufferId = BufferId(3),
+        networkId = NetworkId(1),
+        bufferName = "digitalcircuit",
+        type = Buffer_Type.of(Buffer_Type.QueryBuffer)
+      )
+    ),
+    TestSession.BufferTestData(
+      bufferInfo = BufferInfo(
+        bufferId = BufferId(4),
+        networkId = NetworkId(1),
+        bufferName = "ChanServ",
+        type = Buffer_Type.of(Buffer_Type.QueryBuffer)
+      )
+    )
+  )
+
+  aliases = AliasManager.defaults()
 }
diff --git a/lib/src/test/java/de/kuschku/libquassel/util/TestSession.kt b/lib/src/test/java/de/kuschku/libquassel/util/TestSession.kt
index 0c35beca8009398b396cf80a1b56873e6ad66319..0da086ad59902c804713ec35663bdf9596cf48de 100644
--- a/lib/src/test/java/de/kuschku/libquassel/util/TestSession.kt
+++ b/lib/src/test/java/de/kuschku/libquassel/util/TestSession.kt
@@ -21,13 +21,12 @@ package de.kuschku.libquassel.util
 
 import de.kuschku.libquassel.connection.ConnectionState
 import de.kuschku.libquassel.connection.Features
-import de.kuschku.libquassel.protocol.IdentityId
-import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.libquassel.protocol.QVariantList
-import de.kuschku.libquassel.protocol.QVariantMap
+import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.protocol.message.SignalProxyMessage
+import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.*
+import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
 import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject
 import de.kuschku.libquassel.session.Error
 import de.kuschku.libquassel.session.ISession
@@ -66,8 +65,13 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
         it.objectName == target.objectName
       }
       assertTrue(
-        "SYNC No calls were made on ${target.className}:${target.objectName}",
-        matchingTargetTypes.isNotEmpty()
+        if (matchingTargetTypes.isNotEmpty()) {
+          "SYNC No calls were made on ${target.className}:${target.objectName}, instead only on:\n  ${matchingTargetTypes.map { "${it.className}:${it.objectName}" }.joinToString(
+            "\n  ")}"
+        } else {
+          "SYNC No calls were made on ${target.className}:${target.objectName}"
+        },
+        matchingTargets.isNotEmpty()
       )
 
       val matchingNames = matchingTargets.filter {
@@ -80,7 +84,8 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
       if (!params.isNullOrEmpty()) {
         val calledParams = matchingNames.map(SignalProxyMessage.SyncMessage::params)
         assertTrue(
-          "SYNC ${target.className}:${target.objectName}:$slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString("\n  ")}",
+          "SYNC ${target.className}:${target.objectName}:$slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString(
+            "\n  ")}",
           calledParams.contains(params)
         )
       }
@@ -97,18 +102,37 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
       if (!params.isNullOrEmpty()) {
         val calledParams = matchingNames.map(SignalProxyMessage.RpcCall::params)
         assertTrue(
-          "RPC $slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString("\n  ")}",
+          "RPC $slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString(
+            "\n  ")}",
           calledParams.contains(params)
         )
       }
     }
+
+    fun requestInit(className: String, objectName: String) {
+      val matchingType = initRequest.filter {
+        it.className == className
+      }
+      assertTrue(
+        "InitRequest No data was requested for objects of type $className",
+        matchingType.isNotEmpty()
+      )
+      val matchingCalls = matchingType.filter {
+        it.objectName == objectName
+      }
+      assertTrue(
+        "InitRequest No data was requested for object $className:$objectName, instead only for:\n  ${matchingType.map { "${it.className}:${it.objectName}" }.joinToString(
+          "\n  ")}",
+        matchingCalls.isNotEmpty()
+      )
+    }
   }
 
   class TestEnvironment(private val session: TestSession) :
     SubmissionCallback {
     private val submittedCalls = mutableListOf<SignalProxyMessage>()
 
-    fun run(f: ISession.() -> Unit) : TestEnvironment {
+    fun run(f: ISession.() -> Unit): TestEnvironment {
       session.submissionCallbacks.add(this)
       f.invoke(session)
       session.submissionCallbacks.remove(this)
@@ -156,6 +180,13 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
     live_identities.onNext(Unit)
   }
 
+  fun addIdentity(identity: Identity, initialize: Boolean = false) {
+    identities[identity.id()] = identity
+    if (!initialize)
+      identity.initialized = true
+    synchronize(identity)
+  }
+
   override fun removeIdentity(identityId: IdentityId) {
     val identity = identities.remove(identityId)
     stopSynchronize(identity)
@@ -180,6 +211,13 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
     network_added.onNext(networkId)
   }
 
+  fun addNetwork(network: Network, initialize: Boolean = false) {
+    networks[network.networkId()] = network
+    if (!initialize)
+      network.initialized = true
+    synchronize(network)
+  }
+
   override fun removeNetwork(networkId: NetworkId) {
     val network = networks.remove(networkId)
     stopSynchronize(network)
@@ -194,21 +232,40 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
 
   override val lag = BehaviorSubject.createDefault(0L)
 
+  fun buildNetwork(networkId: NetworkId, f: (Network.() -> Unit)? = null): Network {
+    val network = Network(networkId, proxy)
+    f?.invoke(network)
+    return network
+  }
+
+  fun buildIdentity(identityId: IdentityId, f: (Identity.() -> Unit)? = null): Identity {
+    val identity = Identity(proxy)
+    identity.setId(identityId)
+    f?.invoke(identity)
+    return identity
+  }
+
+  data class BufferTestData(
+    val bufferInfo: BufferInfo,
+    val activity: Message_Types = Message_Type.of(),
+    val lastSeenMsg: MsgId = MsgId(-1),
+    val markerLine: MsgId = MsgId(-1),
+    val highlightCount: Int = 0
+  )
+
   data class TestData(
     val session: TestSession,
     var networks: List<Network> = emptyList(),
-    var identities: List<Identity> = emptyList()
+    var identities: List<Identity> = emptyList(),
+    var buffers: List<BufferTestData> = emptyList(),
+    var aliases: List<IAliasManager.Alias> = emptyList()
   ) {
-    fun buildNetwork(networkId: NetworkId, f: Network.() -> Unit): Network {
-      val network = Network(networkId, session.proxy)
-      f.invoke(network)
-      return network
+    fun buildNetwork(networkId: NetworkId, f: (Network.() -> Unit)? = null): Network {
+      return session.buildNetwork(networkId, f)
     }
 
-    fun buildIdentity(f: Identity.() -> Unit): Identity {
-      val identity = Identity(session.proxy)
-      f.invoke(identity)
-      return identity
+    fun buildIdentity(identityId: IdentityId, f: (Identity.() -> Unit)? = null): Identity {
+      return session.buildIdentity(identityId, f)
     }
 
     fun Network.buildIrcChannel(name: String, f: IrcChannel.() -> Unit): IrcChannel {
@@ -232,13 +289,27 @@ class TestSession : ProtocolHandler({ throw it }), ISession {
     val data = TestData(this)
     f.invoke(data)
     for (network in data.networks) {
-      network.initialized = true
-      networks[network.networkId()] = network
+      addNetwork(network)
     }
     for (identity in data.identities) {
-      identity.initialized = true
-      identities[identity.id()] = identity
+      addIdentity(identity)
     }
+    bufferSyncer.setBufferInfos(data.buffers.map {
+      it.bufferInfo
+    })
+    bufferSyncer.setActivities(data.buffers.map {
+      Pair(it.bufferInfo.bufferId, it.activity)
+    })
+    bufferSyncer.setMarkerLines(data.buffers.map {
+      Pair(it.bufferInfo.bufferId, it.markerLine)
+    })
+    bufferSyncer.setLastSeenMsg(data.buffers.map {
+      Pair(it.bufferInfo.bufferId, it.lastSeenMsg)
+    })
+    bufferSyncer.setHighlightCounts(data.buffers.map {
+      Pair(it.bufferInfo.bufferId, it.highlightCount)
+    })
+    aliasManager.setAliasList(data.aliases)
     return this
   }