Browse Source

Add structured send methods

tags/v0.10.0
Chris Smith 5 years ago
parent
commit
e91342edc9

+ 6
- 0
CHANGELOG View File

3
  * Batch start and end events are no longer included in BatchReceived events
3
  * Batch start and end events are no longer included in BatchReceived events
4
  * Batches now expose complete metadata from their start event
4
  * Batches now expose complete metadata from their start event
5
  * Added support for labelled-replies capability and label message tags
5
  * Added support for labelled-replies capability and label message tags
6
+ * Added new methods for sending raw lines to the IRC server
7
+   * send(tagMap(...), command, arguments) replaces send(line)
8
+   * send(command, arguments) is available if no tags are to be sent
9
+   * the line is built automatically (with spaces/' :' added appropriately)
10
+   * send(line) is deprecated and will be removed after v1.0.0
11
+ * (Internal) Added annotation to track removal of deprecated methods
6
 
12
 
7
 v0.9.0
13
 v0.9.0
8
 
14
 

+ 26
- 0
src/main/kotlin/com/dmdirc/ktirc/IrcClient.kt View File

4
 import com.dmdirc.ktirc.io.CaseMapping
4
 import com.dmdirc.ktirc.io.CaseMapping
5
 import com.dmdirc.ktirc.messages.sendJoin
5
 import com.dmdirc.ktirc.messages.sendJoin
6
 import com.dmdirc.ktirc.model.*
6
 import com.dmdirc.ktirc.model.*
7
+import com.dmdirc.ktirc.util.RemoveIn
7
 
8
 
8
 /**
9
 /**
9
  * Primary interface for interacting with KtIrc.
10
  * Primary interface for interacting with KtIrc.
54
      *
55
      *
55
      * @param message The line to be sent to the IRC server.
56
      * @param message The line to be sent to the IRC server.
56
      */
57
      */
58
+    @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
59
+    @RemoveIn("2.0.0")
57
     fun send(message: String)
60
     fun send(message: String)
58
 
61
 
62
+    /**
63
+     * Sends the given command to the IRC server.
64
+     *
65
+     * This should only be needed to send raw/custom commands; standard messages can be sent using the
66
+     * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
67
+     *
68
+     * @param tags The IRCv3 tags to prefix the message with, if any.
69
+     * @param command The command to be sent
70
+     * @param arguments The arguments to the command.
71
+     */
72
+    fun send(tags: Map<MessageTag, String>, command: String, vararg arguments: String)
73
+
74
+    /**
75
+     * Sends the given command to the IRC server.
76
+     *
77
+     * This should only be needed to send raw/custom commands; standard messages can be sent using the
78
+     * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
79
+     *
80
+     * @param command The command to be sent
81
+     * @param arguments The arguments to the command.
82
+     */
83
+    fun send(command: String, vararg arguments: String) = send(emptyMap(), command, *arguments)
84
+
59
     /**
85
     /**
60
      * Registers a new handler for all events on this connection.
86
      * Registers a new handler for all events on this connection.
61
      *
87
      *

+ 12
- 11
src/main/kotlin/com/dmdirc/ktirc/IrcClientImpl.kt View File

40
     override val userState = UserState { caseMapping }
40
     override val userState = UserState { caseMapping }
41
 
41
 
42
     private val messageHandler = MessageHandler(messageProcessors, eventMutators, eventHandlers)
42
     private val messageHandler = MessageHandler(messageProcessors, eventMutators, eventHandlers)
43
+    private val messageBuilder = MessageBuilder()
43
 
44
 
44
     private val parser = MessageParser()
45
     private val parser = MessageParser()
45
     private var socket: LineBufferedSocket? = null
46
     private var socket: LineBufferedSocket? = null
50
         socket?.sendChannel?.offer(message.toByteArray()) ?: log.warning { "No send channel for message: $message" }
51
         socket?.sendChannel?.offer(message.toByteArray()) ?: log.warning { "No send channel for message: $message" }
51
     }
52
     }
52
 
53
 
54
+    override fun send(tags: Map<MessageTag, String>, command: String, vararg arguments: String) {
55
+        socket?.sendChannel?.offer(messageBuilder.build(tags, command, arguments))
56
+                ?: log.warning { "No send channel for command: $command" }
57
+    }
58
+
53
     // TODO: This will become sendAsync and return a Deferred<IrcEvent>
59
     // TODO: This will become sendAsync and return a Deferred<IrcEvent>
54
-    // TODO: Refactor so that send takes a map of tags and arguments; build the string separately
55
-    internal fun sendWithLabel(message: String) {
56
-        val messageToSend = if (Capability.LabeledResponse in serverState.capabilities.enabledCapabilities) {
57
-            val label = generateLabel(this)
58
-            "@draft/label=$label" + if (message.startsWith('@')) {
59
-                ";${message.substring(1)}"
60
-            } else {
61
-                " $message"
62
-            }
60
+    internal fun sendWithLabel(tags: Map<MessageTag, String>, command: String, vararg arguments: String) {
61
+        val tagseToSend = if (Capability.LabeledResponse in serverState.capabilities.enabledCapabilities) {
62
+            tags + (MessageTag.Label to generateLabel(this))
63
         } else {
63
         } else {
64
-            message
64
+            tags
65
         }
65
         }
66
-        socket?.sendChannel?.offer(messageToSend.toByteArray()) ?: log.warning { "No send channel for message: $message" }
66
+        socket?.sendChannel?.offer(messageBuilder.build(tagseToSend, command, arguments))
67
+                ?: log.warning { "No send channel for command: $command" }
67
     }
68
     }
68
 
69
 
69
     override fun connect() {
70
     override fun connect() {

+ 7
- 3
src/main/kotlin/com/dmdirc/ktirc/events/Events.kt View File

4
 import com.dmdirc.ktirc.model.ConnectionError
4
 import com.dmdirc.ktirc.model.ConnectionError
5
 import com.dmdirc.ktirc.model.ServerFeatureMap
5
 import com.dmdirc.ktirc.model.ServerFeatureMap
6
 import com.dmdirc.ktirc.model.User
6
 import com.dmdirc.ktirc.model.User
7
+import com.dmdirc.ktirc.util.RemoveIn
7
 import java.time.LocalDateTime
8
 import java.time.LocalDateTime
8
 
9
 
9
 /**
10
 /**
24
 sealed class IrcEvent(val metadata: EventMetadata) {
25
 sealed class IrcEvent(val metadata: EventMetadata) {
25
 
26
 
26
     /** The time at which the event occurred. */
27
     /** The time at which the event occurred. */
27
-    @Deprecated("Moved to metadata; to be removed post-1.0.0", replaceWith = ReplaceWith("metadata.time"))
28
+    @Deprecated("Moved to metadata", replaceWith = ReplaceWith("metadata.time"))
29
+    @RemoveIn("2.0.0")
28
     val time: LocalDateTime
30
     val time: LocalDateTime
29
         get() = metadata.time
31
         get() = metadata.time
30
 
32
 
92
 class MessageReceived(metadata: EventMetadata, val user: User, val target: String, val message: String) : IrcEvent(metadata) {
94
 class MessageReceived(metadata: EventMetadata, val user: User, val target: String, val message: String) : IrcEvent(metadata) {
93
 
95
 
94
     /** The message ID of this message. */
96
     /** The message ID of this message. */
95
-    @Deprecated("Moved to metadata; to be removed post-1.0.0", replaceWith = ReplaceWith("metadata.messageId"))
97
+    @Deprecated("Moved to metadata", replaceWith = ReplaceWith("metadata.messageId"))
98
+    @RemoveIn("2.0.0")
96
     val messageId: String?
99
     val messageId: String?
97
         get() = metadata.messageId
100
         get() = metadata.messageId
98
 
101
 
109
 class ActionReceived(metadata: EventMetadata, val user: User, val target: String, val action: String) : IrcEvent(metadata) {
112
 class ActionReceived(metadata: EventMetadata, val user: User, val target: String, val action: String) : IrcEvent(metadata) {
110
 
113
 
111
     /** The message ID of this action. */
114
     /** The message ID of this action. */
112
-    @Deprecated("Moved to metadata; to be removed post-1.0.0", replaceWith = ReplaceWith("metadata.messageId"))
115
+    @Deprecated("Moved to metadata", replaceWith = ReplaceWith("metadata.messageId"))
116
+    @RemoveIn("2.0.0")
113
     val messageId: String?
117
     val messageId: String?
114
         get() = metadata.messageId
118
         get() = metadata.messageId
115
 
119
 

+ 41
- 0
src/main/kotlin/com/dmdirc/ktirc/messages/MessageBuilder.kt View File

1
+package com.dmdirc.ktirc.messages
2
+
3
+import com.dmdirc.ktirc.model.MessageTag
4
+
5
+internal class MessageBuilder {
6
+
7
+    fun build(tags: Map<MessageTag, String>, command: String, arguments: Array<out String>) =
8
+            // TODO: Check line length
9
+            buildString {
10
+                append(tags.toPrefix())
11
+                append(command)
12
+                append(arguments.toSuffix())
13
+            }.toByteArray()
14
+
15
+    private fun Map<MessageTag, String>.toPrefix() = when {
16
+        isEmpty() -> ""
17
+        // TODO: Check if the server actually understands tags here
18
+        // TODO: Check maximum length of tags
19
+        else ->
20
+            map { "${it.key.name}=${it.value.escapeTagValue()}" }
21
+                    .joinToString(separator = ";", prefix = "@", postfix = " ")
22
+    }
23
+
24
+    private fun Array<out String>.toSuffix() = when (size) {
25
+        0 -> ""
26
+        1 -> this[0].asLastParam()
27
+        else -> dropLast(1).joinToString(separator = " ", prefix = " ") + last().asLastParam()
28
+    }
29
+
30
+    private fun String.asLastParam() = when {
31
+        contains(' ') || startsWith(':') -> " :$this"
32
+        else -> " $this"
33
+    }
34
+
35
+    private fun String.escapeTagValue() = replace("\\", "\\\\")
36
+            .replace("\n", "\\n")
37
+            .replace("\r", "\\r")
38
+            .replace(";", "\\:")
39
+            .replace(" ", "\\s")
40
+
41
+}

+ 18
- 29
src/main/kotlin/com/dmdirc/ktirc/messages/MessageBuilders.kt View File

4
 import com.dmdirc.ktirc.model.MessageTag
4
 import com.dmdirc.ktirc.model.MessageTag
5
 
5
 
6
 /** Sends a message to ask the server to list capabilities. */
6
 /** Sends a message to ask the server to list capabilities. */
7
-internal fun IrcClient.sendCapabilityList() = send("CAP LS 302")
7
+internal fun IrcClient.sendCapabilityList() = send("CAP", "LS", "302")
8
 
8
 
9
 /** Sends a message indicating the end of capability negotiation. */
9
 /** Sends a message indicating the end of capability negotiation. */
10
-internal fun IrcClient.sendCapabilityEnd() = send("CAP END")
10
+internal fun IrcClient.sendCapabilityEnd() = send("CAP", "END")
11
 
11
 
12
 /** Sends a message requesting the specified caps are enabled. */
12
 /** Sends a message requesting the specified caps are enabled. */
13
-internal fun IrcClient.sendCapabilityRequest(capabilities: List<String>) = send("CAP REQ :${capabilities.joinToString(" ")}")
13
+internal fun IrcClient.sendCapabilityRequest(capabilities: List<String>) = send("CAP", "REQ", capabilities.joinToString(" "))
14
 
14
 
15
 /** Sends a request to join the given channel. */
15
 /** Sends a request to join the given channel. */
16
-fun IrcClient.sendJoin(channel: String) = send("JOIN :$channel")
16
+fun IrcClient.sendJoin(channel: String) = send("JOIN", channel)
17
 
17
 
18
 /** Sends a request to see the modes of a given target. */
18
 /** Sends a request to see the modes of a given target. */
19
-fun IrcClient.sendModeRequest(target: String) = send("MODE :$target")
19
+fun IrcClient.sendModeRequest(target: String) = send("MODE", target)
20
 
20
 
21
 /** Sends a request to change to the given nickname. */
21
 /** Sends a request to change to the given nickname. */
22
-fun IrcClient.sendNickChange(nick: String) = send("NICK :$nick")
22
+fun IrcClient.sendNickChange(nick: String) = send("NICK", nick)
23
 
23
 
24
 /** Sends the connection password to the server. */
24
 /** Sends the connection password to the server. */
25
-internal fun IrcClient.sendPassword(password: String) = send("PASS :$password")
25
+internal fun IrcClient.sendPassword(password: String) = send("PASS", password)
26
 
26
 
27
 /** Sends a response to a PING event. */
27
 /** Sends a response to a PING event. */
28
-internal fun IrcClient.sendPong(nonce: ByteArray) = send("PONG :${String(nonce)}")
28
+internal fun IrcClient.sendPong(nonce: ByteArray) = send("PONG", String(nonce))
29
 
29
 
30
 /** Sends a CTCP message of the specified [type] and with optional [data] to [target] (a user or a channel). */
30
 /** Sends a CTCP message of the specified [type] and with optional [data] to [target] (a user or a channel). */
31
 fun IrcClient.sendCtcp(target: String, type: String, data: String? = null) =
31
 fun IrcClient.sendCtcp(target: String, type: String, data: String? = null) =
36
 
36
 
37
 /** Sends a private message to a user or channel. */
37
 /** Sends a private message to a user or channel. */
38
 fun IrcClient.sendMessage(target: String, message: String, inReplyTo: String? = null) =
38
 fun IrcClient.sendMessage(target: String, message: String, inReplyTo: String? = null) =
39
-        sendWithTags(mapOf(MessageTag.Reply to inReplyTo), "PRIVMSG $target :$message")
39
+        send(
40
+                inReplyTo?.let { tagMap(MessageTag.Reply to inReplyTo) } ?: emptyMap(),
41
+                "PRIVMSG",
42
+                target,
43
+                message)
40
 
44
 
41
 /**
45
 /**
42
  * Sends a tag-only message.
46
  * Sends a tag-only message.
44
  * If [inReplyTo] is specified then the [MessageTag.Reply] tag will be automatically added.
48
  * If [inReplyTo] is specified then the [MessageTag.Reply] tag will be automatically added.
45
  */
49
  */
46
 fun IrcClient.sendTagMessage(target: String, tags: Map<MessageTag, String>, inReplyTo: String? = null) {
50
 fun IrcClient.sendTagMessage(target: String, tags: Map<MessageTag, String>, inReplyTo: String? = null) {
47
-    sendWithTags(inReplyTo?.let { tags + (MessageTag.Reply to inReplyTo) } ?: tags, "TAGMSG $target")
51
+    send(inReplyTo?.let { tags + (MessageTag.Reply to inReplyTo) } ?: tags, "TAGMSG", target)
48
 }
52
 }
49
 
53
 
50
 /** Sends a message to register a user with the server. */
54
 /** Sends a message to register a user with the server. */
51
-internal fun IrcClient.sendUser(userName: String, realName: String) = send("USER $userName 0 * :$realName")
55
+internal fun IrcClient.sendUser(userName: String, realName: String) = send("USER", userName, "0", "*", realName)
52
 
56
 
53
 /** Starts an authentication request. */
57
 /** Starts an authentication request. */
54
-internal fun IrcClient.sendAuthenticationMessage(data: String = "+") = send("AUTHENTICATE $data")
58
+internal fun IrcClient.sendAuthenticationMessage(data: String = "+") = send("AUTHENTICATE", data)
55
 
59
 
56
 /**
60
 /**
57
- * Sends a message prefixed with some IRCv3 tags.
58
- *
59
- * For convenience, if the value of a tag is `null`, the tag will be omitted. If no tags are present the
60
- * message is sent directly with no prefix.
61
+ * Utility method for creating a map of tags to avoid type inference problems.
61
  */
62
  */
62
-internal fun IrcClient.sendWithTags(tags: Map<MessageTag, String?>, message: String) = tags
63
-        .filterValues { it != null }
64
-        .map { (key, value) -> "${key.name}=${value?.escapeTagValue()}" }
65
-        .joinToString(";")
66
-        .let {
67
-            if (it.isEmpty()) send(message) else send("@$it $message")
68
-        }
69
-
70
-internal fun String.escapeTagValue() = replace("\\", "\\\\")
71
-        .replace("\n", "\\n")
72
-        .replace("\r", "\\r")
73
-        .replace(";", "\\:")
74
-        .replace(" ", "\\s")
63
+fun tagMap(vararg tags: Pair<MessageTag, String>) = mapOf(*tags)

+ 10
- 0
src/main/kotlin/com/dmdirc/ktirc/util/RemoveIn.kt View File

1
+package com.dmdirc.ktirc.util
2
+
3
+/**
4
+ * Documents when a deprecated feature will be removed.
5
+ */
6
+@MustBeDocumented
7
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS,
8
+        AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER,
9
+        AnnotationTarget.TYPEALIAS)
10
+annotation class RemoveIn(val version: String)

+ 30
- 7
src/test/kotlin/com/dmdirc/ktirc/IrcClientImplTest.kt View File

3
 import com.dmdirc.ktirc.events.*
3
 import com.dmdirc.ktirc.events.*
4
 import com.dmdirc.ktirc.io.CaseMapping
4
 import com.dmdirc.ktirc.io.CaseMapping
5
 import com.dmdirc.ktirc.io.LineBufferedSocket
5
 import com.dmdirc.ktirc.io.LineBufferedSocket
6
+import com.dmdirc.ktirc.messages.tagMap
6
 import com.dmdirc.ktirc.model.*
7
 import com.dmdirc.ktirc.model.*
7
 import com.dmdirc.ktirc.util.currentTimeProvider
8
 import com.dmdirc.ktirc.util.currentTimeProvider
8
 import com.dmdirc.ktirc.util.generateLabel
9
 import com.dmdirc.ktirc.util.generateLabel
122
         client.connect()
123
         client.connect()
123
 
124
 
124
         assertEquals("CAP LS 302", String(sendLineChannel.receive()))
125
         assertEquals("CAP LS 302", String(sendLineChannel.receive()))
125
-        assertEquals("NICK :$NICK", String(sendLineChannel.receive()))
126
+        assertEquals("NICK $NICK", String(sendLineChannel.receive()))
126
         assertEquals("USER $USER_NAME 0 * :$REAL_NAME", String(sendLineChannel.receive()))
127
         assertEquals("USER $USER_NAME 0 * :$REAL_NAME", String(sendLineChannel.receive()))
127
     }
128
     }
128
 
129
 
137
         client.connect()
138
         client.connect()
138
 
139
 
139
         assertEquals("CAP LS 302", String(sendLineChannel.receive()))
140
         assertEquals("CAP LS 302", String(sendLineChannel.receive()))
140
-        assertEquals("PASS :$PASSWORD", String(sendLineChannel.receive()))
141
+        assertEquals("PASS $PASSWORD", String(sendLineChannel.receive()))
141
     }
142
     }
142
 
143
 
143
     @Test
144
     @Test
199
         assertLineReceived("testing 123")
200
         assertLineReceived("testing 123")
200
     }
201
     }
201
 
202
 
203
+    @Test
204
+    fun `sends structured text to socket`() = runBlocking {
205
+        val client = IrcClientImpl(normalConfig)
206
+        client.socketFactory = mockSocketFactory
207
+        client.connect()
208
+
209
+        client.send("testing", "123", "456")
210
+
211
+        assertLineReceived("testing 123 456")
212
+    }
213
+
214
+    @Test
215
+    fun `sends structured text to socket with tags`() = runBlocking {
216
+        val client = IrcClientImpl(normalConfig)
217
+        client.socketFactory = mockSocketFactory
218
+        client.connect()
219
+
220
+        client.send(tagMap(MessageTag.AccountName to "acidB"), "testing", "123", "456")
221
+
222
+        assertLineReceived("@account=acidB testing 123 456")
223
+    }
224
+
202
     @Test
225
     @Test
203
     fun `sends text to socket without label if cap is missing`() = runBlocking {
226
     fun `sends text to socket without label if cap is missing`() = runBlocking {
204
         val client = IrcClientImpl(normalConfig)
227
         val client = IrcClientImpl(normalConfig)
205
         client.socketFactory = mockSocketFactory
228
         client.socketFactory = mockSocketFactory
206
         client.connect()
229
         client.connect()
207
 
230
 
208
-        client.sendWithLabel("testing 123")
231
+        client.sendWithLabel(tagMap(), "testing", "123")
209
 
232
 
210
         assertLineReceived("testing 123")
233
         assertLineReceived("testing 123")
211
     }
234
     }
218
         client.serverState.capabilities.enabledCapabilities[Capability.LabeledResponse] = ""
241
         client.serverState.capabilities.enabledCapabilities[Capability.LabeledResponse] = ""
219
         client.connect()
242
         client.connect()
220
 
243
 
221
-        client.sendWithLabel("testing 123")
244
+        client.sendWithLabel(tagMap(), "testing", "123")
222
 
245
 
223
         assertLineReceived("@draft/label=abc123 testing 123")
246
         assertLineReceived("@draft/label=abc123 testing 123")
224
     }
247
     }
231
         client.serverState.capabilities.enabledCapabilities[Capability.LabeledResponse] = ""
254
         client.serverState.capabilities.enabledCapabilities[Capability.LabeledResponse] = ""
232
         client.connect()
255
         client.connect()
233
 
256
 
234
-        client.sendWithLabel("@+test=x testing 123")
257
+        client.sendWithLabel(tagMap(MessageTag.AccountName to "x"), "testing", "123")
235
 
258
 
236
-        assertLineReceived("@draft/label=abc123;+test=x testing 123")
259
+        assertLineReceived("@account=x;draft/label=abc123 testing 123")
237
     }
260
     }
238
 
261
 
239
     @Test
262
     @Test
254
         client.socketFactory = mockSocketFactory
277
         client.socketFactory = mockSocketFactory
255
         client.connect()
278
         client.connect()
256
 
279
 
257
-        (0..100).forEach { client.send("TEST $it") }
280
+        (0..100).forEach { client.send("TEST", "$it") }
258
 
281
 
259
         assertEquals(100, withTimeoutOrNull(500) {
282
         assertEquals(100, withTimeoutOrNull(500) {
260
             var next = 0
283
             var next = 0

+ 10
- 12
src/test/kotlin/com/dmdirc/ktirc/events/EventUtilsTest.kt View File

3
 import com.dmdirc.ktirc.IrcClient
3
 import com.dmdirc.ktirc.IrcClient
4
 import com.dmdirc.ktirc.TestConstants
4
 import com.dmdirc.ktirc.TestConstants
5
 import com.dmdirc.ktirc.io.CaseMapping
5
 import com.dmdirc.ktirc.io.CaseMapping
6
-import com.dmdirc.ktirc.model.ModePrefixMapping
7
-import com.dmdirc.ktirc.model.ServerFeature
8
-import com.dmdirc.ktirc.model.ServerState
9
-import com.dmdirc.ktirc.model.User
6
+import com.dmdirc.ktirc.messages.tagMap
7
+import com.dmdirc.ktirc.model.*
10
 import com.nhaarman.mockitokotlin2.doReturn
8
 import com.nhaarman.mockitokotlin2.doReturn
11
 import com.nhaarman.mockitokotlin2.mock
9
 import com.nhaarman.mockitokotlin2.mock
12
 import com.nhaarman.mockitokotlin2.verify
10
 import com.nhaarman.mockitokotlin2.verify
72
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "Zerocool", "Hack the planet!")
70
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "Zerocool", "Hack the planet!")
73
 
71
 
74
         ircClient.reply(message, "OK")
72
         ircClient.reply(message, "OK")
75
-        verify(ircClient).send("PRIVMSG acidBurn :OK")
73
+        verify(ircClient).send(tagMap(), "PRIVMSG", "acidBurn", "OK")
76
     }
74
     }
77
 
75
 
78
     @Test
76
     @Test
80
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "#TheGibson", "Hack the planet!")
78
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "#TheGibson", "Hack the planet!")
81
 
79
 
82
         ircClient.reply(message, "OK")
80
         ircClient.reply(message, "OK")
83
-        verify(ircClient).send("PRIVMSG #TheGibson :OK")
81
+        verify(ircClient).send(tagMap(), "PRIVMSG", "#TheGibson", "OK")
84
     }
82
     }
85
 
83
 
86
     @Test
84
     @Test
88
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "#TheGibson", "Hack the planet!")
86
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "#TheGibson", "Hack the planet!")
89
 
87
 
90
         ircClient.reply(message, "OK", prefixWithNickname = true)
88
         ircClient.reply(message, "OK", prefixWithNickname = true)
91
-        verify(ircClient).send("PRIVMSG #TheGibson :acidBurn: OK")
89
+        verify(ircClient).send(tagMap(), "PRIVMSG", "#TheGibson", "acidBurn: OK")
92
     }
90
     }
93
 
91
 
94
     @Test
92
     @Test
97
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "Zerocool", "Hack the planet!")
95
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "Zerocool", "Hack the planet!")
98
 
96
 
99
         ircClient.reply(message, "OK")
97
         ircClient.reply(message, "OK")
100
-        verify(ircClient).send("@+draft/reply=abc123 PRIVMSG acidBurn :OK")
98
+        verify(ircClient).send(tagMap(MessageTag.Reply to "abc123"), "PRIVMSG", "acidBurn", "OK")
101
     }
99
     }
102
 
100
 
103
     @Test
101
     @Test
105
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "#TheGibson", "Hack the planet!")
103
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "#TheGibson", "Hack the planet!")
106
 
104
 
107
         ircClient.reply(message, "OK")
105
         ircClient.reply(message, "OK")
108
-        verify(ircClient).send("@+draft/reply=abc123 PRIVMSG #TheGibson :OK")
106
+        verify(ircClient).send(tagMap(MessageTag.Reply to "abc123"), "PRIVMSG", "#TheGibson", "OK")
109
     }
107
     }
110
 
108
 
111
     @Test
109
     @Test
113
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "#TheGibson", "Hack the planet!")
111
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "#TheGibson", "Hack the planet!")
114
 
112
 
115
         ircClient.reply(message, "OK", prefixWithNickname = true)
113
         ircClient.reply(message, "OK", prefixWithNickname = true)
116
-        verify(ircClient).send("@+draft/reply=abc123 PRIVMSG #TheGibson :acidBurn: OK")
114
+        verify(ircClient).send(tagMap(MessageTag.Reply to "abc123"), "PRIVMSG", "#TheGibson", "acidBurn: OK")
117
     }
115
     }
118
 
116
 
119
 
117
 
123
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "msgId"), User("acidBurn"), "Zerocool", "Hack the planet!")
121
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "msgId"), User("acidBurn"), "Zerocool", "Hack the planet!")
124
 
122
 
125
         ircClient.react(message, ":P")
123
         ircClient.react(message, ":P")
126
-        verify(ircClient).send("@+draft/react=:P;+draft/reply=msgId TAGMSG acidBurn")
124
+        verify(ircClient).send(tagMap(MessageTag.React to ":P", MessageTag.Reply to "msgId"), "TAGMSG", "acidBurn")
127
     }
125
     }
128
 
126
 
129
     @Test
127
     @Test
131
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "msgId"), User("acidBurn"), "#TheGibson", "Hack the planet!")
129
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "msgId"), User("acidBurn"), "#TheGibson", "Hack the planet!")
132
 
130
 
133
         ircClient.react(message, ":P")
131
         ircClient.react(message, ":P")
134
-        verify(ircClient).send("@+draft/react=:P;+draft/reply=msgId TAGMSG #TheGibson")
132
+        verify(ircClient).send(tagMap(MessageTag.React to ":P", MessageTag.Reply to "msgId"), "TAGMSG", "#TheGibson")
135
     }
133
     }
136
 
134
 
137
 }
135
 }

+ 11
- 11
src/test/kotlin/com/dmdirc/ktirc/events/handlers/CapabilitiesHandlerTest.kt View File

64
 
64
 
65
         handler.processEvent(ircClient, ServerCapabilitiesFinished(EventMetadata(TestConstants.time)))
65
         handler.processEvent(ircClient, ServerCapabilitiesFinished(EventMetadata(TestConstants.time)))
66
 
66
 
67
-        verify(ircClient).send(argThat { equals("CAP REQ :echo-message account-notify") || equals("CAP REQ :account-notify echo-message") })
67
+        verify(ircClient).send(eq("CAP"), eq("REQ"), argThat { equals("echo-message account-notify") || equals("account-notify echo-message") })
68
     }
68
     }
69
 
69
 
70
     @Test
70
     @Test
71
     fun `sends END when blank capabilities received`() {
71
     fun `sends END when blank capabilities received`() {
72
         handler.processEvent(ircClient, ServerCapabilitiesFinished(EventMetadata(TestConstants.time)))
72
         handler.processEvent(ircClient, ServerCapabilitiesFinished(EventMetadata(TestConstants.time)))
73
 
73
 
74
-        verify(ircClient).send("CAP END")
74
+        verify(ircClient).send("CAP", "END")
75
     }
75
     }
76
 
76
 
77
     @Test
77
     @Test
88
                 Capability.HostsInNamesReply to ""
88
                 Capability.HostsInNamesReply to ""
89
         )))
89
         )))
90
 
90
 
91
-        verify(ircClient).send("CAP END")
91
+        verify(ircClient).send("CAP", "END")
92
     }
92
     }
93
 
93
 
94
     @Test
94
     @Test
99
                 Capability.HostsInNamesReply to ""
99
                 Capability.HostsInNamesReply to ""
100
         )))
100
         )))
101
 
101
 
102
-        verify(ircClient).send("CAP END")
102
+        verify(ircClient).send("CAP", "END")
103
     }
103
     }
104
 
104
 
105
     @Test
105
     @Test
111
                 Capability.HostsInNamesReply to ""
111
                 Capability.HostsInNamesReply to ""
112
         )))
112
         )))
113
 
113
 
114
-        verify(ircClient).send("CAP END")
114
+        verify(ircClient).send("CAP", "END")
115
     }
115
     }
116
 
116
 
117
     @Test
117
     @Test
147
                 Capability.HostsInNamesReply to ""
147
                 Capability.HostsInNamesReply to ""
148
         )))
148
         )))
149
 
149
 
150
-        verify(ircClient).send("AUTHENTICATE mech1")
150
+        verify(ircClient).send("AUTHENTICATE", "mech1")
151
     }
151
     }
152
 
152
 
153
     @Test
153
     @Test
159
                 Capability.HostsInNamesReply to ""
159
                 Capability.HostsInNamesReply to ""
160
         )))
160
         )))
161
 
161
 
162
-        verify(ircClient).send("AUTHENTICATE mech3")
162
+        verify(ircClient).send("AUTHENTICATE", "mech3")
163
     }
163
     }
164
 
164
 
165
     @Test
165
     @Test
201
         serverState.sasl.currentMechanism = null
201
         serverState.sasl.currentMechanism = null
202
         handler.processEvent(ircClient, AuthenticationMessage(EventMetadata(TestConstants.time), "+"))
202
         handler.processEvent(ircClient, AuthenticationMessage(EventMetadata(TestConstants.time), "+"))
203
 
203
 
204
-        verify(ircClient).send("AUTHENTICATE *")
204
+        verify(ircClient).send("AUTHENTICATE", "*")
205
     }
205
     }
206
 
206
 
207
     @Test
207
     @Test
267
     fun `sends END when SASL auth finished`() {
267
     fun `sends END when SASL auth finished`() {
268
         handler.processEvent(ircClient, SaslFinished(EventMetadata(TestConstants.time), true))
268
         handler.processEvent(ircClient, SaslFinished(EventMetadata(TestConstants.time), true))
269
 
269
 
270
-        verify(ircClient).send("CAP END")
270
+        verify(ircClient).send("CAP", "END")
271
     }
271
     }
272
 
272
 
273
     @Test
273
     @Test
299
         serverState.sasl.mechanisms.addAll(listOf(saslMech1, saslMech2, saslMech3))
299
         serverState.sasl.mechanisms.addAll(listOf(saslMech1, saslMech2, saslMech3))
300
         handler.processEvent(ircClient, SaslMechanismNotAvailableError(EventMetadata(TestConstants.time), listOf("mech1", "fake2")))
300
         handler.processEvent(ircClient, SaslMechanismNotAvailableError(EventMetadata(TestConstants.time), listOf("mech1", "fake2")))
301
 
301
 
302
-        verify(ircClient).send("AUTHENTICATE mech1")
302
+        verify(ircClient).send("AUTHENTICATE", "mech1")
303
     }
303
     }
304
 
304
 
305
     @Test
305
     @Test
307
         serverState.sasl.mechanisms.addAll(listOf(saslMech1, saslMech2, saslMech3))
307
         serverState.sasl.mechanisms.addAll(listOf(saslMech1, saslMech2, saslMech3))
308
         handler.processEvent(ircClient, SaslMechanismNotAvailableError(EventMetadata(TestConstants.time), listOf("fake1", "fake2")))
308
         handler.processEvent(ircClient, SaslMechanismNotAvailableError(EventMetadata(TestConstants.time), listOf("fake1", "fake2")))
309
 
309
 
310
-        verify(ircClient).send("CAP END")
310
+        verify(ircClient).send("CAP", "END")
311
     }
311
     }
312
 
312
 
313
     @Test
313
     @Test

+ 3
- 3
src/test/kotlin/com/dmdirc/ktirc/events/handlers/ChannelStateHandlerTest.kt View File

145
 
145
 
146
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
146
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
147
 
147
 
148
-        verify(ircClient).send("MODE :#thegibson")
148
+        verify(ircClient).send("MODE", "#thegibson")
149
     }
149
     }
150
 
150
 
151
     @Test
151
     @Test
158
 
158
 
159
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
159
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
160
 
160
 
161
-        verify(ircClient, never()).send("MODE :#thegibson")
161
+        verify(ircClient, never()).send("MODE", "#thegibson")
162
     }
162
     }
163
 
163
 
164
     @Test
164
     @Test
170
 
170
 
171
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
171
         handler.processEvent(ircClient, ChannelNamesFinished(EventMetadata(TestConstants.time), "#thegibson"))
172
 
172
 
173
-        verify(ircClient, never()).send("MODE :#thegibson")
173
+        verify(ircClient, never()).send("MODE", "#thegibson")
174
     }
174
     }
175
 
175
 
176
     @Test
176
     @Test

+ 1
- 1
src/test/kotlin/com/dmdirc/ktirc/events/handlers/PingHandlerTest.kt View File

18
     @Test
18
     @Test
19
     fun `PingHandler responses to pings with a pong`() = runBlocking {
19
     fun `PingHandler responses to pings with a pong`() = runBlocking {
20
         handler.processEvent(ircClient, PingReceived(EventMetadata(TestConstants.time), "the_plague".toByteArray()))
20
         handler.processEvent(ircClient, PingReceived(EventMetadata(TestConstants.time), "the_plague".toByteArray()))
21
-        verify(ircClient).send("PONG :the_plague")
21
+        verify(ircClient).send("PONG", "the_plague")
22
     }
22
     }
23
 
23
 
24
 }
24
 }

+ 62
- 0
src/test/kotlin/com/dmdirc/ktirc/messages/MessageBuilderTest.kt View File

1
+package com.dmdirc.ktirc.messages
2
+
3
+import com.dmdirc.ktirc.model.MessageTag
4
+import org.junit.jupiter.api.Assertions.assertEquals
5
+import org.junit.jupiter.api.Test
6
+
7
+internal class MessageBuilderTest {
8
+
9
+    private val builder = MessageBuilder()
10
+
11
+    @Test
12
+    fun `builds a command on its own`() =
13
+            assertEquals("TEST", String(builder.build(emptyMap(), "TEST", emptyArray())))
14
+
15
+    @Test
16
+    fun `handles a single argument`() =
17
+            assertEquals("TEST foo", String(builder.build(emptyMap(), "TEST", arrayOf("foo"))))
18
+
19
+    @Test
20
+    fun `handles a single argument starting with a colon`() =
21
+            assertEquals("TEST ::foo", String(builder.build(emptyMap(), "TEST", arrayOf(":foo"))))
22
+
23
+    @Test
24
+    fun `handles a single argument with spaces`() =
25
+            assertEquals("TEST :foo bar", String(builder.build(emptyMap(), "TEST", arrayOf("foo bar"))))
26
+
27
+    @Test
28
+    fun `handles many arguments`() =
29
+            assertEquals("TEST foo bar baz", String(builder.build(emptyMap(), "TEST", arrayOf("foo", "bar", "baz"))))
30
+
31
+    @Test
32
+    fun `handles many arguments with spaces in the last`() =
33
+            assertEquals("TEST foo bar :baz quux", String(builder.build(emptyMap(), "TEST", arrayOf("foo", "bar", "baz quux"))))
34
+
35
+    @Test
36
+    fun `handles single tag`() =
37
+            assertEquals(
38
+                    "@draft/label=abc TEST foo bar",
39
+                    String(builder.build(
40
+                            mapOf(MessageTag.Label to "abc"),
41
+                            "TEST",
42
+                            arrayOf("foo", "bar"))))
43
+
44
+    @Test
45
+    fun `handles multiple tags`() =
46
+            assertEquals(
47
+                    "@draft/label=abc;account=acidB TEST foo bar",
48
+                    String(builder.build(
49
+                            mapOf(MessageTag.Label to "abc", MessageTag.AccountName to "acidB"),
50
+                            "TEST",
51
+                            arrayOf("foo", "bar"))))
52
+
53
+    @Test
54
+    fun `escapes tag values`() =
55
+            assertEquals(
56
+                    "@draft/label=\\\\hack\\sthe\\r\\nplanet\\: TEST foo bar",
57
+                    String(builder.build(
58
+                            mapOf(MessageTag.Label to "\\hack the\r\nplanet;"),
59
+                            "TEST",
60
+                            arrayOf("foo", "bar"))))
61
+
62
+}

+ 21
- 49
src/test/kotlin/com/dmdirc/ktirc/messages/MessageBuildersTest.kt View File

4
 import com.dmdirc.ktirc.model.MessageTag
4
 import com.dmdirc.ktirc.model.MessageTag
5
 import com.nhaarman.mockitokotlin2.mock
5
 import com.nhaarman.mockitokotlin2.mock
6
 import com.nhaarman.mockitokotlin2.verify
6
 import com.nhaarman.mockitokotlin2.verify
7
-import org.junit.jupiter.api.Assertions.assertEquals
8
 import org.junit.jupiter.api.Test
7
 import org.junit.jupiter.api.Test
9
 
8
 
10
 internal class MessageBuildersTest {
9
 internal class MessageBuildersTest {
14
     @Test
13
     @Test
15
     fun `sendCapabilityRequest sends CAP REQ message with single argument`() {
14
     fun `sendCapabilityRequest sends CAP REQ message with single argument`() {
16
         mockClient.sendCapabilityRequest(listOf("a"))
15
         mockClient.sendCapabilityRequest(listOf("a"))
17
-        verify(mockClient).send("CAP REQ :a")
16
+        verify(mockClient).send("CAP", "REQ", "a")
18
     }
17
     }
19
 
18
 
20
     @Test
19
     @Test
21
     fun `sendCapabilityRequest sends CAP REQ message with multiple args`() {
20
     fun `sendCapabilityRequest sends CAP REQ message with multiple args`() {
22
         mockClient.sendCapabilityRequest(listOf("a b c"))
21
         mockClient.sendCapabilityRequest(listOf("a b c"))
23
-        verify(mockClient).send("CAP REQ :a b c")
22
+        verify(mockClient).send("CAP", "REQ", "a b c")
24
     }
23
     }
25
 
24
 
26
     @Test
25
     @Test
27
     fun `sendJoin sends correct JOIN message`() {
26
     fun `sendJoin sends correct JOIN message`() {
28
         mockClient.sendJoin("#TheGibson")
27
         mockClient.sendJoin("#TheGibson")
29
-        verify(mockClient).send("JOIN :#TheGibson")
28
+        verify(mockClient).send("JOIN", "#TheGibson")
30
     }
29
     }
31
 
30
 
32
     @Test
31
     @Test
33
     fun `sendModeRequest sends correct MODE message`() {
32
     fun `sendModeRequest sends correct MODE message`() {
34
         mockClient.sendModeRequest("#TheGibson")
33
         mockClient.sendModeRequest("#TheGibson")
35
-        verify(mockClient).send("MODE :#TheGibson")
34
+        verify(mockClient).send("MODE", "#TheGibson")
36
     }
35
     }
37
 
36
 
38
     @Test
37
     @Test
39
     fun `sendNickChange sends correct NICK message`() {
38
     fun `sendNickChange sends correct NICK message`() {
40
         mockClient.sendNickChange("AcidBurn")
39
         mockClient.sendNickChange("AcidBurn")
41
-        verify(mockClient).send("NICK :AcidBurn")
40
+        verify(mockClient).send("NICK", "AcidBurn")
42
     }
41
     }
43
 
42
 
44
     @Test
43
     @Test
45
     fun `sendPassword sends correct PASS message`() {
44
     fun `sendPassword sends correct PASS message`() {
46
         mockClient.sendPassword("hacktheplanet")
45
         mockClient.sendPassword("hacktheplanet")
47
-        verify(mockClient).send("PASS :hacktheplanet")
46
+        verify(mockClient).send("PASS", "hacktheplanet")
48
     }
47
     }
49
 
48
 
50
     @Test
49
     @Test
51
     fun `sendPong sends correct PONG message`() {
50
     fun `sendPong sends correct PONG message`() {
52
         mockClient.sendPong("abcdef".toByteArray())
51
         mockClient.sendPong("abcdef".toByteArray())
53
-        verify(mockClient).send("PONG :abcdef")
52
+        verify(mockClient).send("PONG", "abcdef")
54
     }
53
     }
55
 
54
 
56
     @Test
55
     @Test
57
     fun `sendMessage sends correct PRIVMSG message`() {
56
     fun `sendMessage sends correct PRIVMSG message`() {
58
         mockClient.sendMessage("acidBurn", "Hack the planet!")
57
         mockClient.sendMessage("acidBurn", "Hack the planet!")
59
-        verify(mockClient).send("PRIVMSG acidBurn :Hack the planet!")
58
+        verify(mockClient).send(tagMap(), "PRIVMSG", "acidBurn", "Hack the planet!")
60
     }
59
     }
61
 
60
 
62
     @Test
61
     @Test
63
     fun `sendMessage sends correct PRIVMSG message with reply to tag`() {
62
     fun `sendMessage sends correct PRIVMSG message with reply to tag`() {
64
         mockClient.sendMessage("acidBurn", "Hack the planet!", "abc123")
63
         mockClient.sendMessage("acidBurn", "Hack the planet!", "abc123")
65
-        verify(mockClient).send("@+draft/reply=abc123 PRIVMSG acidBurn :Hack the planet!")
64
+        verify(mockClient).send(tagMap(MessageTag.Reply to "abc123"), "PRIVMSG", "acidBurn", "Hack the planet!")
66
     }
65
     }
67
 
66
 
68
     @Test
67
     @Test
69
     fun `sendCtcp sends correct CTCP message with no arguments`() {
68
     fun `sendCtcp sends correct CTCP message with no arguments`() {
70
         mockClient.sendCtcp("acidBurn", "ping")
69
         mockClient.sendCtcp("acidBurn", "ping")
71
-        verify(mockClient).send("PRIVMSG acidBurn :\u0001PING\u0001")
70
+        verify(mockClient).send(tagMap(), "PRIVMSG", "acidBurn", "\u0001PING\u0001")
72
     }
71
     }
73
 
72
 
74
     @Test
73
     @Test
75
     fun `sendCtcp sends correct CTCP message with arguments`() {
74
     fun `sendCtcp sends correct CTCP message with arguments`() {
76
         mockClient.sendCtcp("acidBurn", "ping", "12345")
75
         mockClient.sendCtcp("acidBurn", "ping", "12345")
77
-        verify(mockClient).send("PRIVMSG acidBurn :\u0001PING 12345\u0001")
76
+        verify(mockClient).send(tagMap(), "PRIVMSG", "acidBurn", "\u0001PING 12345\u0001")
78
     }
77
     }
79
 
78
 
80
     @Test
79
     @Test
81
     fun `sendAction sends correct action`() {
80
     fun `sendAction sends correct action`() {
82
         mockClient.sendAction("acidBurn", "hacks the planet")
81
         mockClient.sendAction("acidBurn", "hacks the planet")
83
-        verify(mockClient).send("PRIVMSG acidBurn :\u0001ACTION hacks the planet\u0001")
82
+        verify(mockClient).send(tagMap(), "PRIVMSG", "acidBurn", "\u0001ACTION hacks the planet\u0001")
84
     }
83
     }
85
 
84
 
86
     @Test
85
     @Test
87
     fun `sendUser sends correct USER message`() {
86
     fun `sendUser sends correct USER message`() {
88
         mockClient.sendUser("AcidBurn","Kate")
87
         mockClient.sendUser("AcidBurn","Kate")
89
-        verify(mockClient).send("USER AcidBurn 0 * :Kate")
88
+        verify(mockClient).send("USER", "AcidBurn", "0", "*", "Kate")
90
     }
89
     }
91
 
90
 
92
     @Test
91
     @Test
93
     fun `sendUser sends correct AUTHENTICATE message`() {
92
     fun `sendUser sends correct AUTHENTICATE message`() {
94
         mockClient.sendAuthenticationMessage("SCRAM-MD5")
93
         mockClient.sendAuthenticationMessage("SCRAM-MD5")
95
-        verify(mockClient).send("AUTHENTICATE SCRAM-MD5")
94
+        verify(mockClient).send("AUTHENTICATE", "SCRAM-MD5")
96
     }
95
     }
97
 
96
 
98
     @Test
97
     @Test
99
     fun `sendUser sends correct blank AUTHENTICATE message`() {
98
     fun `sendUser sends correct blank AUTHENTICATE message`() {
100
         mockClient.sendAuthenticationMessage()
99
         mockClient.sendAuthenticationMessage()
101
-        verify(mockClient).send("AUTHENTICATE +")
102
-    }
103
-
104
-    @Test
105
-    fun `sendWithTag sends message without tags`() {
106
-        mockClient.sendWithTags(emptyMap(), "PING")
107
-        verify(mockClient).send("PING")
108
-    }
109
-
110
-    @Test
111
-    fun `sendWithTag sends message with single tag`() {
112
-        mockClient.sendWithTags(mapOf(MessageTag.MessageId to "abc"), "PING")
113
-        verify(mockClient).send("@draft/msgid=abc PING")
114
-    }
115
-
116
-    @Test
117
-    fun `sendWithTag sends message with multiple tag`() {
118
-        mockClient.sendWithTags(mapOf(MessageTag.MessageId to "abc", MessageTag.AccountName to "foo"), "PING")
119
-        verify(mockClient).send("@draft/msgid=abc;account=foo PING")
120
-    }
121
-
122
-    @Test
123
-    fun `sendWithTag ignores tags with null values`() {
124
-        mockClient.sendWithTags(mapOf(MessageTag.MessageId to null, MessageTag.AccountName to "foo"), "PING")
125
-        verify(mockClient).send("@account=foo PING")
100
+        verify(mockClient).send("AUTHENTICATE", "+")
126
     }
101
     }
127
 
102
 
128
     @Test
103
     @Test
129
     fun `sendTagMessage sends tags`() {
104
     fun `sendTagMessage sends tags`() {
130
-        mockClient.sendTagMessage("#thegibson", mapOf(MessageTag.MessageId to "id", MessageTag.AccountName to "foo"))
131
-        verify(mockClient).send("@draft/msgid=id;account=foo TAGMSG #thegibson")
105
+        val tags = mapOf(MessageTag.MessageId to "id", MessageTag.AccountName to "foo")
106
+        mockClient.sendTagMessage("#thegibson", tags)
107
+        verify(mockClient).send(tags, "TAGMSG", "#thegibson")
132
     }
108
     }
133
 
109
 
134
     @Test
110
     @Test
135
     fun `sendTagMessage sends tags with reply ID`() {
111
     fun `sendTagMessage sends tags with reply ID`() {
136
-        mockClient.sendTagMessage("#thegibson", mapOf(MessageTag.MessageId to "id", MessageTag.AccountName to "foo"), "otherid")
137
-        verify(mockClient).send("@draft/msgid=id;account=foo;+draft/reply=otherid TAGMSG #thegibson")
138
-    }
139
-
140
-    @Test
141
-    fun `escapes tag values`() {
142
-        assertEquals("\\\\hack\\sthe\\r\\nplanet\\:", "\\hack the\r\nplanet;".escapeTagValue())
112
+        val tags = mapOf(MessageTag.MessageId to "id", MessageTag.AccountName to "foo")
113
+        mockClient.sendTagMessage("#thegibson", tags, "otherId")
114
+        verify(mockClient).send(tags + (MessageTag.Reply to "otherId"), "TAGMSG", "#thegibson")
143
     }
115
     }
144
 
116
 
145
 }
117
 }

+ 1
- 1
src/test/kotlin/com/dmdirc/ktirc/sasl/ExternalMechanismTest.kt View File

14
 
14
 
15
         mechanism.handleAuthenticationEvent(client, null)
15
         mechanism.handleAuthenticationEvent(client, null)
16
 
16
 
17
-        verify(client).send("AUTHENTICATE +")
17
+        verify(client).send("AUTHENTICATE", "+")
18
     }
18
     }
19
 
19
 
20
 }
20
 }

+ 3
- 9
src/test/kotlin/com/dmdirc/ktirc/sasl/PlainMechanismTest.kt View File

3
 import com.dmdirc.ktirc.IrcClient
3
 import com.dmdirc.ktirc.IrcClient
4
 import com.dmdirc.ktirc.SaslConfig
4
 import com.dmdirc.ktirc.SaslConfig
5
 import com.dmdirc.ktirc.model.ServerState
5
 import com.dmdirc.ktirc.model.ServerState
6
-import com.nhaarman.mockitokotlin2.argumentCaptor
7
-import com.nhaarman.mockitokotlin2.doReturn
8
-import com.nhaarman.mockitokotlin2.mock
9
-import com.nhaarman.mockitokotlin2.verify
6
+import com.nhaarman.mockitokotlin2.*
10
 import org.junit.jupiter.api.Assertions.assertEquals
7
 import org.junit.jupiter.api.Assertions.assertEquals
11
 import org.junit.jupiter.api.Test
8
 import org.junit.jupiter.api.Test
12
 
9
 
27
         mechanism.handleAuthenticationEvent(ircClient, null)
24
         mechanism.handleAuthenticationEvent(ircClient, null)
28
 
25
 
29
         val captor = argumentCaptor<String>()
26
         val captor = argumentCaptor<String>()
30
-        verify(ircClient).send(captor.capture())
31
-        val parts = captor.firstValue.split(' ')
32
-        assertEquals("AUTHENTICATE", parts[0])
33
-
34
-        val data = String(parts[1].fromBase64()).split('\u0000')
27
+        verify(ircClient).send(eq("AUTHENTICATE"), captor.capture())
28
+        val data = String(captor.firstValue.fromBase64()).split('\u0000')
35
         assertEquals("acidB", data[0])
29
         assertEquals("acidB", data[0])
36
         assertEquals("acidB", data[1])
30
         assertEquals("acidB", data[1])
37
         assertEquals("HackThePlan3t!", data[2])
31
         assertEquals("HackThePlan3t!", data[2])

+ 5
- 5
src/test/kotlin/com/dmdirc/ktirc/sasl/SaslMechanismTest.kt View File

31
     fun `base64 encodes authentication data`() {
31
     fun `base64 encodes authentication data`() {
32
         val client = mock<IrcClient>()
32
         val client = mock<IrcClient>()
33
         client.sendAuthenticationData("abcdef")
33
         client.sendAuthenticationData("abcdef")
34
-        verify(client).send("AUTHENTICATE YWJjZGVm")
34
+        verify(client).send("AUTHENTICATE", "YWJjZGVm")
35
     }
35
     }
36
 
36
 
37
     @Test
37
     @Test
39
         val client = mock<IrcClient>()
39
         val client = mock<IrcClient>()
40
         client.sendAuthenticationData("abcdef".repeat(120))
40
         client.sendAuthenticationData("abcdef".repeat(120))
41
         with (inOrder(client)) {
41
         with (inOrder(client)) {
42
-            verify(client, times(2)).send("AUTHENTICATE ${"YWJjZGVm".repeat(50)}")
43
-            verify(client).send("AUTHENTICATE ${"YWJjZGVm".repeat(20)}")
42
+            verify(client, times(2)).send("AUTHENTICATE", "YWJjZGVm".repeat(50))
43
+            verify(client).send("AUTHENTICATE", "YWJjZGVm".repeat(20))
44
         }
44
         }
45
     }
45
     }
46
 
46
 
49
         val client = mock<IrcClient>()
49
         val client = mock<IrcClient>()
50
         client.sendAuthenticationData("abcdef".repeat(50))
50
         client.sendAuthenticationData("abcdef".repeat(50))
51
         with (inOrder(client)) {
51
         with (inOrder(client)) {
52
-            verify(client).send("AUTHENTICATE ${"YWJjZGVm".repeat(50)}")
53
-            verify(client).send("AUTHENTICATE +")
52
+            verify(client).send("AUTHENTICATE", "YWJjZGVm".repeat(50))
53
+            verify(client).send("AUTHENTICATE", "+")
54
         }
54
         }
55
     }
55
     }
56
 
56
 

+ 13
- 13
src/test/kotlin/com/dmdirc/ktirc/sasl/ScramMechanismTest.kt View File

26
         mechanism.handleAuthenticationEvent(ircClient, "+".toByteArray())
26
         mechanism.handleAuthenticationEvent(ircClient, "+".toByteArray())
27
 
27
 
28
         val nonce = (serverState.sasl.mechanismState as ScramState).clientNonce
28
         val nonce = (serverState.sasl.mechanismState as ScramState).clientNonce
29
-        verify(ircClient).send("AUTHENTICATE ${"n,,n=user,r=$nonce".toByteArray().toBase64()}")
29
+        verify(ircClient).send("AUTHENTICATE", "n,,n=user,r=$nonce".toByteArray().toBase64())
30
     }
30
     }
31
 
31
 
32
     @Test
32
     @Test
40
 
40
 
41
         mechanism.handleAuthenticationEvent(ircClient, "m=future".toByteArray())
41
         mechanism.handleAuthenticationEvent(ircClient, "m=future".toByteArray())
42
 
42
 
43
-        verify(ircClient).send("AUTHENTICATE *")
43
+        verify(ircClient).send("AUTHENTICATE", "*")
44
     }
44
     }
45
 
45
 
46
     @Test
46
     @Test
54
 
54
 
55
         mechanism.handleAuthenticationEvent(ircClient, "e=whoops".toByteArray())
55
         mechanism.handleAuthenticationEvent(ircClient, "e=whoops".toByteArray())
56
 
56
 
57
-        verify(ircClient).send("AUTHENTICATE *")
57
+        verify(ircClient).send("AUTHENTICATE", "*")
58
     }
58
     }
59
 
59
 
60
     @Test
60
     @Test
68
 
68
 
69
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92".toByteArray())
69
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92".toByteArray())
70
 
70
 
71
-        verify(ircClient).send("AUTHENTICATE *")
71
+        verify(ircClient).send("AUTHENTICATE", "*")
72
     }
72
     }
73
 
73
 
74
     @Test
74
     @Test
82
 
82
 
83
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=leet".toByteArray())
83
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=leet".toByteArray())
84
 
84
 
85
-        verify(ircClient).send("AUTHENTICATE *")
85
+        verify(ircClient).send("AUTHENTICATE", "*")
86
     }
86
     }
87
 
87
 
88
     @Test
88
     @Test
96
 
96
 
97
         mechanism.handleAuthenticationEvent(ircClient, "rs=QSXCR+Q6sek8bf92,i=4096".toByteArray())
97
         mechanism.handleAuthenticationEvent(ircClient, "rs=QSXCR+Q6sek8bf92,i=4096".toByteArray())
98
 
98
 
99
-        verify(ircClient).send("AUTHENTICATE *")
99
+        verify(ircClient).send("AUTHENTICATE", "*")
100
     }
100
     }
101
 
101
 
102
     @Test
102
     @Test
110
 
110
 
111
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,i=4096".toByteArray())
111
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,i=4096".toByteArray())
112
 
112
 
113
-        verify(ircClient).send("AUTHENTICATE *")
113
+        verify(ircClient).send("AUTHENTICATE", "*")
114
     }
114
     }
115
 
115
 
116
     @Test
116
     @Test
145
 
145
 
146
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096".toByteArray())
146
         mechanism.handleAuthenticationEvent(ircClient, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096".toByteArray())
147
 
147
 
148
-        verify(ircClient).send("AUTHENTICATE ${"c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=".toByteArray().toBase64()}")
148
+        verify(ircClient).send("AUTHENTICATE", "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=".toByteArray().toBase64())
149
     }
149
     }
150
 
150
 
151
     @Test
151
     @Test
159
 
159
 
160
         mechanism.handleAuthenticationEvent(ircClient, "m=future".toByteArray())
160
         mechanism.handleAuthenticationEvent(ircClient, "m=future".toByteArray())
161
 
161
 
162
-        verify(ircClient).send("AUTHENTICATE *")
162
+        verify(ircClient).send("AUTHENTICATE", "*")
163
     }
163
     }
164
 
164
 
165
     @Test
165
     @Test
173
 
173
 
174
         mechanism.handleAuthenticationEvent(ircClient, "e=whoops".toByteArray())
174
         mechanism.handleAuthenticationEvent(ircClient, "e=whoops".toByteArray())
175
 
175
 
176
-        verify(ircClient).send("AUTHENTICATE *")
176
+        verify(ircClient).send("AUTHENTICATE", "*")
177
     }
177
     }
178
 
178
 
179
     @Test
179
     @Test
190
 
190
 
191
         mechanism.handleAuthenticationEvent(ircClient, "".toByteArray())
191
         mechanism.handleAuthenticationEvent(ircClient, "".toByteArray())
192
 
192
 
193
-        verify(ircClient).send("AUTHENTICATE *")
193
+        verify(ircClient).send("AUTHENTICATE", "*")
194
     }
194
     }
195
 
195
 
196
     @Test
196
     @Test
207
 
207
 
208
         mechanism.handleAuthenticationEvent(ircClient, "v=rmF9pqV8S7suAoZWja4dJRkF=".toByteArray())
208
         mechanism.handleAuthenticationEvent(ircClient, "v=rmF9pqV8S7suAoZWja4dJRkF=".toByteArray())
209
 
209
 
210
-        verify(ircClient).send("AUTHENTICATE *")
210
+        verify(ircClient).send("AUTHENTICATE", "*")
211
     }
211
     }
212
 
212
 
213
     @Test
213
     @Test
224
 
224
 
225
         mechanism.handleAuthenticationEvent(ircClient, "v=rmF9pqV8S7suAoZWja4dJRkFsKQ=".toByteArray())
225
         mechanism.handleAuthenticationEvent(ircClient, "v=rmF9pqV8S7suAoZWja4dJRkFsKQ=".toByteArray())
226
 
226
 
227
-        verify(ircClient).send("AUTHENTICATE +")
227
+        verify(ircClient).send("AUTHENTICATE", "+")
228
     }
228
     }
229
 
229
 
230
 }
230
 }

Loading…
Cancel
Save