Browse Source

Part handling

tags/v0.1.0
Chris Smith 5 years ago
parent
commit
0309a660cd

+ 12
- 0
src/main/kotlin/com/dmdirc/ktirc/events/ChannelStateHandler.kt View File

@@ -13,6 +13,7 @@ class ChannelStateHandler : EventHandler {
13 13
     override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
14 14
         when (event) {
15 15
             is ChannelJoined -> handleJoin(client, event)
16
+            is ChannelParted -> handlePart(client, event)
16 17
             is ChannelNamesReceived -> handleNamesReceived(client, event)
17 18
             is ChannelNamesFinished -> handleNamesFinished(client, event)
18 19
         }
@@ -27,6 +28,17 @@ class ChannelStateHandler : EventHandler {
27 28
         client.channelState[event.channel]?.let { it.users += ChannelUser(event.user.nickname) }
28 29
     }
29 30
 
31
+    private fun handlePart(client: IrcClient, event: ChannelParted) {
32
+        if (client.isLocalUser(event.user)) {
33
+            log.info { "Left channel: ${event.channel}" }
34
+            client.channelState -= event.channel
35
+        } else {
36
+            client.channelState[event.channel]?.let {
37
+                it.users -= event.user.nickname
38
+            }
39
+        }
40
+    }
41
+
30 42
     private fun handleNamesReceived(client: IrcClient, event: ChannelNamesReceived) {
31 43
         val channel = client.channelState[event.channel] ?: return
32 44
 

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

@@ -23,6 +23,9 @@ data class PingReceived(val nonce: ByteArray) : IrcEvent()
23 23
 /** Raised when a user joins a channel. */
24 24
 data class ChannelJoined(val user: User, val channel: String) : IrcEvent()
25 25
 
26
+/** Raised when a user leaves a channel. */
27
+data class ChannelParted(val user: User, val channel: String, val reason: String = "") : IrcEvent()
28
+
26 29
 /** Raised when a batch of the channel's member list has been received. More batches may follow. */
27 30
 data class ChannelNamesReceived(val channel: String, val names: List<String>) : IrcEvent()
28 31
 

+ 1
- 0
src/main/kotlin/com/dmdirc/ktirc/messages/MessageProcessor.kt View File

@@ -21,6 +21,7 @@ val messageProcessors = setOf(
21 21
         ISupportProcessor(),
22 22
         JoinProcessor(),
23 23
         NamesProcessor(),
24
+        PartProcessor(),
24 25
         PingProcessor(),
25 26
         WelcomeProcessor()
26 27
 )

+ 21
- 0
src/main/kotlin/com/dmdirc/ktirc/messages/PartProcessor.kt View File

@@ -0,0 +1,21 @@
1
+package com.dmdirc.ktirc.messages
2
+
3
+import com.dmdirc.ktirc.events.ChannelParted
4
+import com.dmdirc.ktirc.io.IrcMessage
5
+import com.dmdirc.ktirc.model.asUser
6
+
7
+class PartProcessor : MessageProcessor {
8
+
9
+    override val commands = arrayOf("PART")
10
+
11
+    override fun process(message: IrcMessage) = message.prefix?.let {
12
+        listOf(ChannelParted(it.asUser(), message.channel, message.reason))
13
+    } ?: emptyList()
14
+
15
+    private val IrcMessage.channel
16
+        get() = String(params[0])
17
+
18
+    private val IrcMessage.reason
19
+        get() = if (params.size > 1) String(params[1]) else ""
20
+
21
+}

+ 2
- 2
src/main/kotlin/com/dmdirc/ktirc/model/Maps.kt View File

@@ -13,8 +13,8 @@ abstract class CaseInsensitiveMap<T>(private val caseMappingProvider: () -> Case
13 13
         values.add(value)
14 14
     }
15 15
 
16
-    operator fun minusAssign(state: T) {
17
-        values.removeIf { caseMappingProvider().areEquivalent(nameOf(it), nameOf(state)) }
16
+    operator fun minusAssign(name: String) {
17
+        values.removeIf { caseMappingProvider().areEquivalent(nameOf(it), name) }
18 18
     }
19 19
 
20 20
     operator fun contains(name: String) = get(name) != null

+ 21
- 0
src/test/kotlin/com/dmdirc/ktirc/events/ChannelStateHandlerTest.kt View File

@@ -100,4 +100,25 @@ internal class ChannelStateHandlerTest {
100 100
         assertEquals("", channel.users["cerealKiller"]?.modes)
101 101
     }
102 102
 
103
+    @Test
104
+    fun `ChannelStateHandler removes state object for local parts`() = runBlocking {
105
+        val channel = ChannelState("#thegibson") { CaseMapping.Rfc }
106
+        channelStateMap += channel
107
+
108
+        handler.processEvent(ircClient, ChannelParted(User("acidburn", "libby", "root.localhost"), "#thegibson"))
109
+
110
+        assertFalse("#thegibson" in channelStateMap)
111
+    }
112
+
113
+    @Test
114
+    fun `ChannelStateHandler removes user from channel member list for remote parts`() = runBlocking {
115
+        val channel = ChannelState("#thegibson") { CaseMapping.Rfc }
116
+        channel.users += ChannelUser("ZeroCool")
117
+        channelStateMap += channel
118
+
119
+        handler.processEvent(ircClient, ChannelParted(User("zerocool", "dade", "root.localhost"), "#thegibson"))
120
+
121
+        assertFalse("zerocool" in channel.users)
122
+    }
123
+
103 124
 }

+ 34
- 0
src/test/kotlin/com/dmdirc/ktirc/messages/PartProcessorTest.kt View File

@@ -0,0 +1,34 @@
1
+package com.dmdirc.ktirc.messages
2
+
3
+import com.dmdirc.ktirc.events.ChannelParted
4
+import com.dmdirc.ktirc.io.IrcMessage
5
+import com.dmdirc.ktirc.model.User
6
+import org.junit.jupiter.api.Assertions
7
+import org.junit.jupiter.api.Test
8
+
9
+internal class PartProcessorTest {
10
+
11
+    @Test
12
+    fun `PartProcessor raises part event without message`() {
13
+        val events = PartProcessor().process(
14
+                IrcMessage(null, "acidburn!libby@root.localhost".toByteArray(), "PART", listOf("#crashandburn".toByteArray())))
15
+        Assertions.assertEquals(1, events.size)
16
+        Assertions.assertEquals(ChannelParted(User("acidburn", "libby", "root.localhost"), "#crashandburn"), events[0])
17
+    }
18
+
19
+    @Test
20
+    fun `PartProcessor raises part event with message`() {
21
+        val events = PartProcessor().process(
22
+                IrcMessage(null, "acidburn!libby@root.localhost".toByteArray(), "PART", listOf("#crashandburn".toByteArray(), "Hack the planet!".toByteArray())))
23
+        Assertions.assertEquals(1, events.size)
24
+        Assertions.assertEquals(ChannelParted(User("acidburn", "libby", "root.localhost"), "#crashandburn", "Hack the planet!"), events[0])
25
+    }
26
+
27
+    @Test
28
+    fun `PartProcessor does nothing if prefix missing`() {
29
+        val events = JoinProcessor().process(
30
+                IrcMessage(null, null, "PART", listOf("#crashandburn".toByteArray())))
31
+        Assertions.assertEquals(0, events.size)
32
+    }
33
+
34
+}

+ 23
- 22
src/test/kotlin/com/dmdirc/ktirc/model/MapsTest.kt View File

@@ -7,21 +7,23 @@ import org.junit.jupiter.api.assertThrows
7 7
 
8 8
 internal class CaseInsensitiveMapTest {
9 9
 
10
+    private data class Wrapper(val name: String)
11
+
10 12
     private var caseMapping = CaseMapping.Rfc
11
-    private val map = object : CaseInsensitiveMap<String>({ caseMapping }, { str -> str.substring(0, 4) }) {}
13
+    private val map = object : CaseInsensitiveMap<Wrapper>({ caseMapping }, { it -> it.name }) {}
12 14
 
13 15
     @Test
14 16
     fun `CaseInsensitiveMap stores values`() {
15
-        val value = "acidBurn"
17
+        val value = Wrapper("acidBurn")
16 18
 
17 19
         map += value
18 20
 
19
-        assertSame(value, map["acid"])
21
+        assertSame(value, map["acidBurn"])
20 22
     }
21 23
 
22 24
     @Test
23 25
     fun `CaseInsensitiveMap disallows the same value twice`() {
24
-        val value = "acidBurn"
26
+        val value = Wrapper("acidBurn")
25 27
 
26 28
         map += value
27 29
 
@@ -32,26 +34,26 @@ internal class CaseInsensitiveMapTest {
32 34
 
33 35
     @Test
34 36
     fun `CaseInsensitiveMap retrieves values using differently cased keys`() {
35
-        val value = "[acidBurn]"
37
+        val value = Wrapper("[acidBurn]")
36 38
         map += value
37 39
 
38
-        assertSame(value, map["{ACI"])
40
+        assertSame(value, map["{ACIDBURN}"])
39 41
     }
40 42
 
41 43
     @Test
42 44
     fun `CaseInsensitiveMap retrieves values if the casemapping changes`() {
43
-        val value = "[acidBurn]"
45
+        val value = Wrapper("[acidBurn]")
44 46
         map += value
45 47
 
46 48
         caseMapping = CaseMapping.Ascii
47 49
 
48
-        assertSame(value, map["[ACI"])
49
-        assertNull(map["{aci"])
50
+        assertSame(value, map["[ACIDBURN]"])
51
+        assertNull(map["{acidburn}"])
50 52
     }
51 53
 
52 54
     @Test
53 55
     fun `CaseInsensitiveMap retrieves null if value not found`() {
54
-        val value = "[acidBurn]"
56
+        val value = Wrapper("[acidBurn]")
55 57
         map += value
56 58
 
57 59
         assertNull(map["acidBurn"])
@@ -60,19 +62,18 @@ internal class CaseInsensitiveMapTest {
60 62
 
61 63
     @Test
62 64
     fun `CaseInsensitiveMap removes values`() {
63
-        map += "acidBurn"
65
+        map += Wrapper("acidBurn")
64 66
         map -= "ACIDburn"
65 67
 
66 68
         assertNull(map["acidBurn"])
67
-        assertNull(map["ACIDburn"])
68 69
     }
69 70
 
70 71
     @Test
71 72
     fun `CaseInsensitiveMap can be iterated`() {
72
-        map += "acidBurn"
73
-        map += "zeroCool"
73
+        map += Wrapper("acidBurn")
74
+        map += Wrapper("zeroCool")
74 75
 
75
-        val names = map.toList()
76
+        val names = map.map { it.name }.toList()
76 77
         assertEquals(2, names.size)
77 78
         assertTrue(names.contains("acidBurn"))
78 79
         assertTrue(names.contains("zeroCool"))
@@ -80,21 +81,21 @@ internal class CaseInsensitiveMapTest {
80 81
 
81 82
     @Test
82 83
     fun `ChannelInsensitiveMap indicates if it contains a value or not`() {
83
-        map += "acidBurn"
84
+        map += Wrapper("acidBurn")
84 85
 
85
-        assertTrue("acid" in map)
86
-        assertFalse("theP" in map)
86
+        assertTrue("acidBurn" in map)
87
+        assertFalse("thePlague" in map)
87 88
     }
88 89
 
89 90
     @Test
90 91
     fun `ChannelInsensitiveMap can be cleared`() {
91
-        map += "acidBurn"
92
-        map += "zeroCool"
92
+        map += Wrapper("acidBurn")
93
+        map += Wrapper("zeroCool")
93 94
 
94 95
         map.clear()
95 96
 
96
-        assertFalse("acid" in map)
97
-        assertFalse("zero" in map)
97
+        assertFalse("acidBurn" in map)
98
+        assertFalse("zeroCool" in map)
98 99
         assertEquals(0, map.count())
99 100
     }
100 101
 

Loading…
Cancel
Save