From e9d6ec96486f77be1076be43991b8281dc12cb79 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sat, 13 Feb 2021 02:20:08 +0100
Subject: [PATCH] Improved further testing

---
 .gitlab-ci.yml                                |  2 +-
 .../primitive/DateSerializerTest.kt           | 59 ++++++++++++
 .../primitive/DateTimeSerializerTest.kt       | 11 +++
 .../DccIpDetectionModeSerializerTest.kt       | 10 +++
 .../DccPortSelectionModeSerializerTest.kt     |  9 ++
 .../primitive/HandshakeMapSerializerTest.kt   | 89 +++++++++++++++++++
 .../primitive/TimeSerializerTest.kt           | 56 ++++++++++++
 .../testutil/matchers/TemporalMatcher.kt      | 15 ++--
 .../protocol/testutil/qtSerializerTest.kt     |  6 +-
 9 files changed, 248 insertions(+), 9 deletions(-)
 create mode 100644 protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateSerializerTest.kt
 create mode 100644 protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/HandshakeMapSerializerTest.kt
 create mode 100644 protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/TimeSerializerTest.kt

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b80cf777f..bdcd7fd57 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -34,7 +34,7 @@ test:
     - name: "k8r.eu/justjanne/quassel-docker:v0.13.1"
       alias: "quasselcore"
   variables:
-    QUASSEL_CONTAINER: "quasselcore:4242"
+    QUASSEL_CONTAINER: "quasselcore"
     SSL_CERT_DATA: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZIekNDQXdlZ0F3SUJBZ0lVRVYvUmY1RGNlUWhqdWwyeXFIRGEvT0RyNStZd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0hqRWNNQm9HQTFVRUF3d1RjWFZoYzNObGJIUmxjM1F1YVc1MllXeHBaREFnRncweU1UQXlNRGd5TXpNNQpNalJhR0E4eU1USXhNREV4TlRJek16a3lORm93SGpFY01Cb0dBMVVFQXd3VGNYVmhjM05sYkhSbGMzUXVhVzUyCllXeHBaRENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFNMk9aVGFlNEJLenBwQjIKbkVGMmUyb0dMbDFZR2FDZnFhVmVRaktOUzNEWThmaklHOWxiNmhEekUxTW5lb0d0b3U3VGFmV3ZxaDJ1MVE4cAphUk5wY1crZnRUcWNVZWNHUHVNVFFISFNXalpKRG9jdkgydkc1eE00OHU1RHFMTlVUaHM3ZUVvUGlzN0FHcHVzCjd4bTh3bWpHb2tLWVpiNldkWEdMY09FUExiMlpTUUg0TVJIa0FNdE0xekYzL0wwYll6UkxpbDkrYVE2eTBQMy8KNGhSZlVpeTVaa0lpUFMzK2ZKUE9qL1phQUJ1a0x0ZmZXaWNiZUF2TkRrN0pwMkZ2b1ZmWFBYVTE0Q1hRYVYxNgpCaGZDYldIYW1VTTRkMFpXdTg1SjhKYm9uK0pSZm1JdmcrMHo0bmxaYUo2YTIzbmtPNGxqTDZJS2R3bEVVWWJNCnVaNGJpbUN4bWsyZzN0MjdEeERCWUFldWRDUVlRanZsQTdmWWY5YjJ0QmpkdlZ4N0JSeUZrMDlaK3pTV0tYVngKNjdpTDVuVVJZOGlPWStzSEY3dC9EL3ZiRHgxL25Ea1haUHhFbDFqWmxEbnUyeENrTThzWWdvY1hzZmpJYVczZgoxZGNHSjZscjUwZzY5TGdUQkJ1VDJEYjNMaTkxbkFyM3MrVjVVcmYxQ2NUTUZpcE5BZGVZM3FONzE3THpLc0pTCkZwakF0dlVKUWhQaW45SXMwQVprWUNyRHhJWVpKWWdRWmFlRENyWFJRd29TOHFJaFhXYmdIWFJQVVR3Z0d6bVMKb2c2MityZnduM0pEUkRLT0d1aVlJYzh1aEJqMG1PT1YvR0JlZ0ZnMWNza2FYK0VNdmR1cngyanlOYzZ5MUpPRwpXSkhaMmN0TVNIbGttNC92RzlsRUhvVzQzSGNQQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRNHVLckltalV2CkMvVEpoYjAzSTNZSkVqZ2pyakFmQmdOVkhTTUVHREFXZ0JRNHVLckltalV2Qy9USmhiMDNJM1lKRWpnanJqQVAKQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUNNYWhxWTFMVmRTbnk5b2M3QgpBR0VUNVkvc1RkQUxaTi9Hc2xZV2pZOWlUTng0a1h6NnUwNjU0b25EVEJIWjZjKzgrZG1aZFdGcmRQVHpKdUpYCmRCNEhxUXlZMnRMaFIzTjQ0RjZMUmt4OTdrbGJ2U3NjTUpyM1FLNDM0NEF0a3NiRXExQkdlRENtNVZlYVpaSlUKQStXU05YakpDMjJFRlI1UkxmdGRBclJxdUpWY3dDRFBXSTFsZi9pdi9pWEpQcHY4TXE1cUZwWTFBZ3VzaS9zdgpQTE82R1ZWMnFQQURvSTBOamdZQ2pKMlZWSlFlSGFzRkNDK2l6aWhtclRRVU1jNEcvSkY5Z0hNUE9MUm9mbTMyCnpNUThMSytpV2E5cCtWb1JiZG5zV0R3NEZ5OXMzNFZYdVQ1aWpBejZLYlE4djlhbFF2NlZmWXduWkNyeWx5S0gKSzN2V2c3ZzF0bHlNWlA3RXh6SGZ1NDI4bFZtWVpiZjFrN0dVQSsyUXU5cy9qUGZzendRemREbnI1ZE45akNVagpDSXFMWG9IWmV5SWMyQ3h1MUtNYVp2a1BWbjIvekpVYTNSTkxmY2wrMXBHT0N3YVVkNWxjR3RkenJrLzlsWndSCnpIaDludlFXUEFFMnIzNkU3Q3RPZ3kwdU1JZkZkTm5EYzFpWUtVMkk5MDc1aytibzd5NHp2TzlnUXgzZG1reFUKU0NtMnNLUXprU2NTQlB0Q0J0c2ZLZk40Y3NMNUZ5TGV2bDdDNWl6cFFxdENocUxadTlYWEROVlRFN2pkNDhXeQpWcklsQkdId0dra3NtWVVxQUxJODFidkJhT1oxR3l0QUlNYlJOUThZUkxJUHZqdUwvQ29yZnFyUjVrRUtYcXNkCmVadzN3NXFHQVNnNlhrMGQ5T3hLeWpIS2VRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
     SSL_KEY_DATA: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRRE5qbVUybnVBU3M2YVEKZHB4QmRudHFCaTVkV0JtZ242bWxYa0l5alV0dzJQSDR5QnZaVytvUTh4TlRKM3FCcmFMdTAybjFyNm9kcnRVUApLV2tUYVhGdm43VTZuRkhuQmo3akUwQngwbG8yU1E2SEx4OXJ4dWNUT1BMdVE2aXpWRTRiTzNoS0Q0ck93QnFiCnJPOFp2TUpveHFKQ21HVytsblZ4aTNEaER5MjltVWtCK0RFUjVBRExUTmN4ZC95OUcyTTBTNHBmZm1rT3N0RDkKLytJVVgxSXN1V1pDSWowdC9ueVR6by8yV2dBYnBDN1gzMW9uRzNnTHpRNU95YWRoYjZGWDF6MTFOZUFsMEdsZAplZ1lYd20xaDJwbERPSGRHVnJ2T1NmQ1c2Si9pVVg1aUw0UHRNK0o1V1dpZW10dDU1RHVKWXkraUNuY0pSRkdHCnpMbWVHNHBnc1pwTm9ON2R1dzhRd1dBSHJuUWtHRUk3NVFPMzJIL1c5clFZM2IxY2V3VWNoWk5QV2ZzMGxpbDEKY2V1NGkrWjFFV1BJam1QckJ4ZTdmdy83Mnc4ZGY1dzVGMlQ4UkpkWTJaUTU3dHNRcERQTEdJS0hGN0g0eUdsdAozOVhYQmllcGErZElPdlM0RXdRYms5ZzI5eTR2ZFp3Szk3UGxlVkszOVFuRXpCWXFUUUhYbU42amU5ZXk4eXJDClVoYVl3TGIxQ1VJVDRwL1NMTkFHWkdBcXc4U0dHU1dJRUdXbmd3cTEwVU1LRXZLaUlWMW00QjEwVDFFOElCczUKa3FJT3R2cTM4Sjl5UTBReWpocm9tQ0hQTG9RWTlKampsZnhnWG9CWU5YTEpHbC9oREwzYnE4ZG84alhPc3RTVApobGlSMmRuTFRFaDVaSnVQN3h2WlJCNkZ1TngzRHdJREFRQUJBb0lDQUExeGFKRWY1c3VTVUN4V2RYV2FpQXV4CkI4czIvY1lSYXdqVGwwU3pGT0gyYml5MCtZMUhnNUZFTkZsVjFaOHhlZHhnbXlka0s1M3hWeUc4dFpCOWJ0dTcKK0NBekpQQVU2bnZ6UUYyeFFoRVd5Z3B4UEg3UjdUN0dsS3ljWkNZR04yMTBnRE5udk00MHBnalVVSGJBYjM1bQpyeW5ueVkralMxNzNuWlE2WitWa1p1L29DVjJBS2NVaDYxamkzZmFJR2Y3TGllc2cyMElJMDc0b3crSk5NWlNYCk0yYlQwbWgxb2pRUWFEM1dPUGVWenpKeSt2UmZ5WVFNRHdsOENxUkdwcWlWL1FEeld3dGVDK1gvR3ZMbTFqeDIKRFZ2bUQzYmNLVUFlZWN1RXZ5QVA4RkgvaFlNM3gzSGtOUUZhWTB3ZmJ2MVhMVUJOcXVkQ1BvcXdUTnRZTmI1cQo3L0lEUkphQVh2MDE2WEhkMzFBSFB0Ynp3bEx6dEZpVHljbm1ML2V4ZnhaREVYYUFVMjhDNVB1WXlMUU5xbTdzCms2QTlCdE5Zd2NmZmJzMlR5QXE2UmdPUXMyRVJXZEhoazhzeVBOd0JkZ2VYVFhTTHF1YlREODd5U2IvWWZMaFkKL1kvbzkxYTBONEFoSkpEZjVqSnhKZmt6RGZSd0lpam81bW5VU3BrRXRkNDh1UjE0c3RzeU9MdEZXUmwrb2NsTgpvOHJDandhdUhHN0FlRnB6MWhkaDJDUWUwdE1vaGYvVG51U3BEeG9rSlF3bVRJS2dYZ3Vic2xmSHRub1cwS0ZrCmpLaHdRcDJyMysxbW54T1MxbnFGVXRuUytHcTZ2WVkvbFQ3cTZuQ2pLS21sbDdjMW4xNFB0eCtVNklvQnJhcDEKcXQ4MWx0eG5UdllJb3JNR3VncGhBb0lCQVFELzQ1VGZTZDUrRytWYzJpOXJHazdYTjNhZ1drbVF0Sld0MTlORgpPN3NGZlBSM2JBOUpxSTNZQWw3ejRodnU0blRRSEVXTU5VeERwRGpnNS9DRW95YXI0V2N4TUFRODVKMHcyTGNNCklYU09JQ2JwV0haeDFUaUFqLzZpQWpnaGZ6WW1RUGNvUVhzNUdMbGdOOElMNitqSkdja2FjVWRKSkw4Ykc1VUgKb2JqWWc4WmMxRDNxUEVuTG9iTDhLdC9peFMrbHFzVncrRkRGMzVhbElVTUQwWkpyU1U5NG5ETnF0K0hDRTF4UApNRm1XWXN5NjhleTAzZ3hDMnZ3Myt0VERzMCs1MjFsLzB5dyttL0Y0cC85MkJIbmsvSnRhOGVnRi80bW9KbCtUCmo0QUhuWWlDcEgrNk8xS1FrdW04MkhrQkdiTUhrYjZpMGdNTXRMYkM1akh4R29aNUFvSUJBUUROcFRsWE9sZDEKOWt6b0lJNlpEVVFVRXVISWQ5QWRqQ243YmVraTJQWk9pcTMxajY3UWlTb0NJQUt0RmhyYjhQakp5YXhOWUthcwpOWGs2UDZNRDVnVkRRb2plQnYyNGNheUdHOTVGQ1VZdElWRDJIcm03L3NSMndrSlJ2QlJPbFlha1JDL3prUGtHCmR5RXRmaXZJVUJ6bkJNNE1JM2d4NzQxbEJWRnBwQWRxdzJxTjZKUU1vVVZBb0VQa2lFZzd3eStmUVVXejJPTXIKdloxeUlQeEpEaDJjN1BLSVVmN3g2SDA4VEhPWFZaK3NXem9GSFo0Q1ZzSGJzMjNaM0lSTHdUNFlEK1RkRCtpbgp6TWExbTE0ZTN4dHQ1cUxwRSt6ZVNCL1dVV1pLcFNsZ1VLaFJ5bGdkcWIvcjg1UklXN29hV2s3SUNmQ2E5WUwxCmplRHlMeVl1YmFmSEFvSUJBRGhiaFZSUVRxSnp2bVplMzRhMU9wd0g2U2FUL0JQVTBncUJ1RlJOUFhtTjljRy8KbVBaZUd5OXlCanVzbHY1Yi9lSS85OGxUaThKeUR0enArSDBkK2N4dFRtNzA1bG9LOTl2a1B4eDYyZExibmZaUwp0M09HeEhUOFFkYW9xbmdtTG1UcWRnVDF0dy95TkJITzlmdnVMMHpyVXZGeDlZTlVob3FQM3BqWnMzNXNOMm9HCmpNUmtGdFMwZmxrdmtETy92aWk4bmRPdHZReDNuQlF1YVRZVUdDMXM3Z1hnVVNxMTZSRDNkcU15UU9qd1JhcisKMFdWY2FsTG5MQm1nTXZBUE5BWDVHNU1kaldjVXJYQW5nQW9jSGtTaXBneTNycVJ6alh2dFI2dVdOVnA0QmJMUQpUQmxXSzI4UURFNjlWcGs1Y2NhL0FMK1hoWGhzN0x1c08xK2d1ZkVDZ2dFQWZHZ0xBMkVSRGhUZHU4UU9ZRHJ0ClIzT1EwYlRoMnk0eks1NzNYaFNCRlV6Q0puOHcwNGxYTjRmajlwQWIyWml5K1dnZTY0U2Y4Q2c5V1dhc0dLeXIKM0YvQTZ3aXhyMFpkaDVnT1pCZFRNL1FteFc0YkVNYjBWWi81ZlBiYUZoeFJJc2o1ZFZEcnhlU0YxcjZ3Zi9NdgpPUGJvSytHOVVnQkl1cWQzOC8rK1dQRTFZZm9rcm10VnVOMzdsS0o1aUdYeFJsZTNjakN3WllMRllBamlkdE9xClNJZnp4VkpOZUUwY2prRDE0TVIwMzFFbERYazRZTlBaWFM3ME1zczc0WlJiR3pWcVQrM1M0c2g0SWQrSEZnZ0UKMFB5bzYzWVpZdk9oQndlaGFXRDNZZ1FKZjhsNGV5RjVNS1hmdTlKNkNIMC9rYmFwcnlUOWY4M0FHdU01SnZkQgpld0tDQVFBb1ZOK0hTL2FmMk8wOSszVEV0Rnl2NG01b3pGQjZudGFDMTJkaHJib1Z3QXc4TVBMR1hhRXFzZlBWCkw5T1JNQTZsUkwrNE9JbzJGY002VGtsRC9yTUFIci9iOVZ0V291OEVSZWlPUjF6U2d0N29wQ1o2d0xoQm5wOVAKbXN6MXB1UC9PK1NSM2xyY1FPbUVUTUs3b2Zxb2V3ZW01cnowQ21UcmFYcXJlSHV6UlgrYy9uV1FxbUpEeU44bwpOZUhoRzVzSXRJaGVQcE5RK1FjUGV6VnlsKyt2TUhGd09POTJvK2kvejd6SDZ1Y1IrZzhPUjQxdlhqSVFFUDVuCjV3OU9HeU94VmZnRmhPNlErQ1VmSXMzSk1sd28vWGt3RnAyTkpvaE5XQVB6UEl5SjVWOVhwSmt1YVdKMTdjL1UKandmWU56Tmx2MXBEeVZHQWFJOG9NRFhSTWFaMwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
     SSL_REQUIRED: "true"
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateSerializerTest.kt
new file mode 100644
index 000000000..9555fc2c6
--- /dev/null
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateSerializerTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.justjanne.libquassel.protocol.serializers.primitive
+
+import de.justjanne.libquassel.protocol.serializers.QtSerializers
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.matchers.TemporalMatcher
+import de.justjanne.libquassel.protocol.testutil.qtSerializerTest
+import de.justjanne.libquassel.protocol.variant.QtType
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import org.threeten.bp.*
+import org.threeten.bp.chrono.JapaneseDate
+import org.threeten.bp.temporal.Temporal
+
+class DateSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      DateSerializer,
+      QtSerializers.find<LocalDate>(QtType.QDate),
+    )
+  }
+
+  @Test
+  fun testEpoch() = qtSerializerTest(
+    DateSerializer,
+    LocalDate
+      .of(1970, 1, 1),
+    byteBufferOf(0, 37, 61, -116),
+    matcher = ::TemporalMatcher
+  )
+
+  @Test
+  fun testNormalCase() = qtSerializerTest(
+    DateSerializer,
+    LocalDate
+      .of(2019, Month.JANUARY, 15),
+    byteBufferOf(0, 37, -125, -125),
+    matcher = ::TemporalMatcher
+  )
+}
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt
index f69dbb502..bc4478086 100644
--- a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DateTimeSerializerTest.kt
@@ -104,6 +104,17 @@ class DateTimeSerializerTest {
     matcher = ::TemporalMatcher
   )
 
+  @Test
+  fun testInvalidDateTime() = qtSerializerTest(
+    DateTimeSerializer,
+    LocalDateTime
+      .of(2019, Month.JANUARY, 15, 20, 25),
+    byteBufferOf(0x00u, 0x25u, 0x83u, 0x83u, 0x04u, 0x61u, 0x85u, 0x60u, 0x09u),
+    matcher = ::TemporalMatcher,
+    serializeFeatureSet = null,
+    featureSets = emptyList(),
+  )
+
   @Test
   fun testOldJavaDate() {
     assertThrows<IllegalArgumentException>("Unsupported Format: org.threeten.bp.chrono.JapaneseDate") {
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccIpDetectionModeSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccIpDetectionModeSerializerTest.kt
index 639511ce7..4c1ea014b 100644
--- a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccIpDetectionModeSerializerTest.kt
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccIpDetectionModeSerializerTest.kt
@@ -18,6 +18,7 @@
  */
 package de.justjanne.libquassel.protocol.serializers.primitive
 
+import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.serializers.QuasselSerializers
 import de.justjanne.libquassel.protocol.testutil.byteBufferOf
 import de.justjanne.libquassel.protocol.testutil.quasselSerializerTest
@@ -50,4 +51,13 @@ class DccIpDetectionModeSerializerTest {
     DccIpDetectionMode.Manual,
     byteBufferOf(0x01u)
   )
+
+  @Test
+  fun testNull() = quasselSerializerTest(
+    DccIpDetectionModeSerializer,
+    null,
+    byteBufferOf(0x00u),
+    deserializeFeatureSet = null,
+    featureSets = emptyList(),
+  )
 }
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccPortSelectionModeSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccPortSelectionModeSerializerTest.kt
index ec9b2c6ca..3101e381f 100644
--- a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccPortSelectionModeSerializerTest.kt
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/DccPortSelectionModeSerializerTest.kt
@@ -50,4 +50,13 @@ class DccPortSelectionModeSerializerTest {
     DccPortSelectionMode.Manual,
     byteBufferOf(0x01u)
   )
+
+  @Test
+  fun testNull() = quasselSerializerTest(
+    DccPortSelectionModeSerializer,
+    null,
+    byteBufferOf(0x00u),
+    deserializeFeatureSet = null,
+    featureSets = emptyList(),
+  )
 }
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/HandshakeMapSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/HandshakeMapSerializerTest.kt
new file mode 100644
index 000000000..161f36e19
--- /dev/null
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/HandshakeMapSerializerTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.justjanne.libquassel.protocol.serializers.primitive
+
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.matchers.MapMatcher
+import de.justjanne.libquassel.protocol.testutil.qtSerializerTest
+import de.justjanne.libquassel.protocol.variant.QtType
+import de.justjanne.libquassel.protocol.variant.qVariant
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+class HandshakeMapSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      QVariantMapSerializer.qtType,
+      HandshakeMapSerializer.qtType,
+    )
+    assertEquals(
+      QVariantMapSerializer.javaType,
+      HandshakeMapSerializer.javaType,
+    )
+  }
+
+  @Test
+  fun testEmpty() = qtSerializerTest(
+    HandshakeMapSerializer,
+    mapOf(),
+    byteBufferOf(0, 0, 0, 0),
+    supportsVariant = false
+  )
+
+  @Test
+  fun testNormal() = qtSerializerTest(
+    HandshakeMapSerializer,
+    mapOf(
+      "Username" to qVariant("AzureDiamond", QtType.QString),
+      "Password" to qVariant("hunter2", QtType.QString)
+    ),
+    byteBufferOf(0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x41, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x44, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x68, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x32),
+    ::MapMatcher,
+    supportsVariant = false
+  )
+
+  @Test
+  fun testNullKey() = qtSerializerTest(
+    HandshakeMapSerializer,
+    mapOf(
+      "" to qVariant<String?>(null, QtType.QString)
+    ),
+    byteBufferOf(
+      // length
+      0x00u, 0x00u, 0x00u, 0x02u,
+      // type of value
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      // isNull of value
+      0x00u,
+      // length of key
+      0xFFu, 0xFFu, 0xFFu, 0xFFu,
+      // type of value
+      0x00u, 0x00u, 0x00u, 0x0Au,
+      // isNull of value
+      0x00u,
+      // length of value
+      0xFFu, 0xFFu, 0xFFu, 0xFFu
+    ),
+    ::MapMatcher,
+    serializeFeatureSet = null,
+    supportsVariant = false,
+  )
+}
+
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/TimeSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/TimeSerializerTest.kt
new file mode 100644
index 000000000..3cf0ee7d1
--- /dev/null
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/serializers/primitive/TimeSerializerTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.justjanne.libquassel.protocol.serializers.primitive
+
+import de.justjanne.libquassel.protocol.serializers.QtSerializers
+import de.justjanne.libquassel.protocol.testutil.byteBufferOf
+import de.justjanne.libquassel.protocol.testutil.matchers.TemporalMatcher
+import de.justjanne.libquassel.protocol.testutil.qtSerializerTest
+import de.justjanne.libquassel.protocol.variant.QtType
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import org.threeten.bp.LocalTime
+
+class TimeSerializerTest {
+  @Test
+  fun testIsRegistered() {
+    assertEquals(
+      TimeSerializer,
+      QtSerializers.find<LocalTime>(QtType.QTime),
+    )
+  }
+
+  @Test
+  fun testEpoch() = qtSerializerTest(
+    TimeSerializer,
+    LocalTime
+      .of(0, 0),
+    byteBufferOf(0, 0, 0, 0),
+    matcher = ::TemporalMatcher
+  )
+
+  @Test
+  fun testNormalCase() = qtSerializerTest(
+    TimeSerializer,
+    LocalTime
+      .of(20, 25),
+    byteBufferOf(0x04u, 0x61u, 0x85u, 0x60u),
+    matcher = ::TemporalMatcher
+  )
+}
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/matchers/TemporalMatcher.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/matchers/TemporalMatcher.kt
index 884daba32..6732f87c9 100644
--- a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/matchers/TemporalMatcher.kt
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/matchers/TemporalMatcher.kt
@@ -20,15 +20,12 @@ package de.justjanne.libquassel.protocol.testutil.matchers
 
 import org.hamcrest.BaseMatcher
 import org.hamcrest.Description
-import org.threeten.bp.Instant
-import org.threeten.bp.LocalDateTime
-import org.threeten.bp.OffsetDateTime
-import org.threeten.bp.ZonedDateTime
+import org.threeten.bp.*
 import org.threeten.bp.temporal.Temporal
 
-class TemporalMatcher(
-  private val expected: Temporal
-) : BaseMatcher<Temporal>() {
+class TemporalMatcher<T: Temporal>(
+  private val expected: T
+) : BaseMatcher<T>() {
   override fun describeTo(description: Description?) {
     description?.appendText(expected.toString())
   }
@@ -43,6 +40,10 @@ class TemporalMatcher(
         expected == item
       expected is LocalDateTime && item is LocalDateTime ->
         expected == item
+      expected is LocalTime && item is LocalTime ->
+        expected == item
+      expected is LocalDate && item is LocalDate ->
+        expected == item
       expected is Instant && item is Instant ->
         expected == item
       else ->
diff --git a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/qtSerializerTest.kt b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/qtSerializerTest.kt
index 20865fc7f..545c9d66a 100644
--- a/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/qtSerializerTest.kt
+++ b/protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/qtSerializerTest.kt
@@ -19,6 +19,7 @@
 package de.justjanne.libquassel.protocol.testutil
 
 import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.contentToString
 import de.justjanne.libquassel.protocol.serializers.primitive.QtSerializer
 import org.hamcrest.Matcher
 import java.nio.ByteBuffer
@@ -31,6 +32,7 @@ fun <T : Any?> qtSerializerTest(
   featureSets: List<FeatureSet> = listOf(FeatureSet.none(), FeatureSet.all()),
   deserializeFeatureSet: FeatureSet? = FeatureSet.all(),
   serializeFeatureSet: FeatureSet? = FeatureSet.all(),
+  supportsVariant: Boolean = true,
 ) {
   if (encoded != null) {
     if (deserializeFeatureSet != null) {
@@ -46,6 +48,8 @@ fun <T : Any?> qtSerializerTest(
   }
   for (featureSet in featureSets) {
     testQtSerializerDirect(serializer, value, featureSet, matcher?.invoke(value))
-    testQtSerializerVariant(serializer, value, featureSet, matcher?.invoke(value))
+    if (supportsVariant) {
+      testQtSerializerVariant(serializer, value, featureSet, matcher?.invoke(value))
+    }
   }
 }
-- 
GitLab