소스 검색

Part handling

tags/v0.1.0
Chris Smith 5 년 전
부모
커밋
0309a660cd

+ 12
- 0
src/main/kotlin/com/dmdirc/ktirc/events/ChannelStateHandler.kt 파일 보기

13
     override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
13
     override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
14
         when (event) {
14
         when (event) {
15
             is ChannelJoined -> handleJoin(client, event)
15
             is ChannelJoined -> handleJoin(client, event)
16
+            is ChannelParted -> handlePart(client, event)
16
             is ChannelNamesReceived -> handleNamesReceived(client, event)
17
             is ChannelNamesReceived -> handleNamesReceived(client, event)
17
             is ChannelNamesFinished -> handleNamesFinished(client, event)
18
             is ChannelNamesFinished -> handleNamesFinished(client, event)
18
         }
19
         }
27
         client.channelState[event.channel]?.let { it.users += ChannelUser(event.user.nickname) }
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
     private fun handleNamesReceived(client: IrcClient, event: ChannelNamesReceived) {
42
     private fun handleNamesReceived(client: IrcClient, event: ChannelNamesReceived) {
31
         val channel = client.channelState[event.channel] ?: return
43
         val channel = client.channelState[event.channel] ?: return
32
 
44
 

+ 3
- 0
src/main/kotlin/com/dmdirc/ktirc/events/Events.kt 파일 보기

23
 /** Raised when a user joins a channel. */
23
 /** Raised when a user joins a channel. */
24
 data class ChannelJoined(val user: User, val channel: String) : IrcEvent()
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
 /** Raised when a batch of the channel's member list has been received. More batches may follow. */
29
 /** Raised when a batch of the channel's member list has been received. More batches may follow. */
27
 data class ChannelNamesReceived(val channel: String, val names: List<String>) : IrcEvent()
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 파일 보기

21
         ISupportProcessor(),
21
         ISupportProcessor(),
22
         JoinProcessor(),
22
         JoinProcessor(),
23
         NamesProcessor(),
23
         NamesProcessor(),
24
+        PartProcessor(),
24
         PingProcessor(),
25
         PingProcessor(),
25
         WelcomeProcessor()
26
         WelcomeProcessor()
26
 )
27
 )

+ 21
- 0
src/main/kotlin/com/dmdirc/ktirc/messages/PartProcessor.kt 파일 보기

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 파일 보기

13
         values.add(value)
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
     operator fun contains(name: String) = get(name) != null
20
     operator fun contains(name: String) = get(name) != null

+ 21
- 0
src/test/kotlin/com/dmdirc/ktirc/events/ChannelStateHandlerTest.kt 파일 보기

100
         assertEquals("", channel.users["cerealKiller"]?.modes)
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 파일 보기

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 파일 보기

7
 
7
 
8
 internal class CaseInsensitiveMapTest {
8
 internal class CaseInsensitiveMapTest {
9
 
9
 
10
+    private data class Wrapper(val name: String)
11
+
10
     private var caseMapping = CaseMapping.Rfc
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
     @Test
15
     @Test
14
     fun `CaseInsensitiveMap stores values`() {
16
     fun `CaseInsensitiveMap stores values`() {
15
-        val value = "acidBurn"
17
+        val value = Wrapper("acidBurn")
16
 
18
 
17
         map += value
19
         map += value
18
 
20
 
19
-        assertSame(value, map["acid"])
21
+        assertSame(value, map["acidBurn"])
20
     }
22
     }
21
 
23
 
22
     @Test
24
     @Test
23
     fun `CaseInsensitiveMap disallows the same value twice`() {
25
     fun `CaseInsensitiveMap disallows the same value twice`() {
24
-        val value = "acidBurn"
26
+        val value = Wrapper("acidBurn")
25
 
27
 
26
         map += value
28
         map += value
27
 
29
 
32
 
34
 
33
     @Test
35
     @Test
34
     fun `CaseInsensitiveMap retrieves values using differently cased keys`() {
36
     fun `CaseInsensitiveMap retrieves values using differently cased keys`() {
35
-        val value = "[acidBurn]"
37
+        val value = Wrapper("[acidBurn]")
36
         map += value
38
         map += value
37
 
39
 
38
-        assertSame(value, map["{ACI"])
40
+        assertSame(value, map["{ACIDBURN}"])
39
     }
41
     }
40
 
42
 
41
     @Test
43
     @Test
42
     fun `CaseInsensitiveMap retrieves values if the casemapping changes`() {
44
     fun `CaseInsensitiveMap retrieves values if the casemapping changes`() {
43
-        val value = "[acidBurn]"
45
+        val value = Wrapper("[acidBurn]")
44
         map += value
46
         map += value
45
 
47
 
46
         caseMapping = CaseMapping.Ascii
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
     @Test
54
     @Test
53
     fun `CaseInsensitiveMap retrieves null if value not found`() {
55
     fun `CaseInsensitiveMap retrieves null if value not found`() {
54
-        val value = "[acidBurn]"
56
+        val value = Wrapper("[acidBurn]")
55
         map += value
57
         map += value
56
 
58
 
57
         assertNull(map["acidBurn"])
59
         assertNull(map["acidBurn"])
60
 
62
 
61
     @Test
63
     @Test
62
     fun `CaseInsensitiveMap removes values`() {
64
     fun `CaseInsensitiveMap removes values`() {
63
-        map += "acidBurn"
65
+        map += Wrapper("acidBurn")
64
         map -= "ACIDburn"
66
         map -= "ACIDburn"
65
 
67
 
66
         assertNull(map["acidBurn"])
68
         assertNull(map["acidBurn"])
67
-        assertNull(map["ACIDburn"])
68
     }
69
     }
69
 
70
 
70
     @Test
71
     @Test
71
     fun `CaseInsensitiveMap can be iterated`() {
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
         assertEquals(2, names.size)
77
         assertEquals(2, names.size)
77
         assertTrue(names.contains("acidBurn"))
78
         assertTrue(names.contains("acidBurn"))
78
         assertTrue(names.contains("zeroCool"))
79
         assertTrue(names.contains("zeroCool"))
80
 
81
 
81
     @Test
82
     @Test
82
     fun `ChannelInsensitiveMap indicates if it contains a value or not`() {
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
     @Test
90
     @Test
90
     fun `ChannelInsensitiveMap can be cleared`() {
91
     fun `ChannelInsensitiveMap can be cleared`() {
91
-        map += "acidBurn"
92
-        map += "zeroCool"
92
+        map += Wrapper("acidBurn")
93
+        map += Wrapper("zeroCool")
93
 
94
 
94
         map.clear()
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
         assertEquals(0, map.count())
99
         assertEquals(0, map.count())
99
     }
100
     }
100
 
101
 

Loading…
취소
저장