Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package com.dmdirc.ktirc
  2. import com.dmdirc.ktirc.events.EventHandler
  3. import com.dmdirc.ktirc.events.ServerWelcome
  4. import com.dmdirc.ktirc.io.CaseMapping
  5. import com.dmdirc.ktirc.io.LineBufferedSocket
  6. import com.dmdirc.ktirc.model.Profile
  7. import com.dmdirc.ktirc.model.Server
  8. import com.dmdirc.ktirc.model.ServerFeature
  9. import com.dmdirc.ktirc.model.User
  10. import com.nhaarman.mockitokotlin2.*
  11. import kotlinx.coroutines.channels.Channel
  12. import kotlinx.coroutines.launch
  13. import kotlinx.coroutines.runBlocking
  14. import org.junit.jupiter.api.Assertions.*
  15. import org.junit.jupiter.api.Test
  16. import org.junit.jupiter.api.assertThrows
  17. internal class IrcClientImplTest {
  18. companion object {
  19. private const val HOST = "thegibson.com"
  20. private const val PORT = 12345
  21. private const val NICK = "AcidBurn"
  22. private const val REAL_NAME = "Kate Libby"
  23. private const val USER_NAME = "acidb"
  24. private const val PASSWORD = "HackThePlanet"
  25. }
  26. private val readLineChannel = Channel<ByteArray>(10)
  27. private val mockSocket = mock<LineBufferedSocket> {
  28. on { readLines(any()) } doReturn readLineChannel
  29. }
  30. private val mockSocketFactory = mock<(String, Int) -> LineBufferedSocket> {
  31. on { invoke(HOST, PORT) } doReturn mockSocket
  32. }
  33. private val mockEventHandler = mock<EventHandler>()
  34. @Test
  35. fun `IrcClientImpl uses socket factory to create a new socket on connect`() {
  36. runBlocking {
  37. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  38. client.socketFactory = mockSocketFactory
  39. readLineChannel.close()
  40. client.connect()
  41. verify(mockSocketFactory).invoke(HOST, PORT)
  42. }
  43. }
  44. @Test
  45. fun `IrcClientImpl throws if socket already exists`() {
  46. runBlocking {
  47. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  48. client.socketFactory = mockSocketFactory
  49. readLineChannel.close()
  50. client.connect()
  51. assertThrows<IllegalStateException> {
  52. runBlocking {
  53. client.connect()
  54. }
  55. }
  56. }
  57. }
  58. @Test
  59. fun `IrcClientImpl sends basic connection strings`() {
  60. runBlocking {
  61. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  62. client.socketFactory = mockSocketFactory
  63. readLineChannel.close()
  64. client.connect()
  65. with(inOrder(mockSocket).verify(mockSocket)) {
  66. sendLine("CAP LS 302")
  67. sendLine("NICK :$NICK")
  68. sendLine("USER $USER_NAME localhost $HOST :$REAL_NAME")
  69. }
  70. }
  71. }
  72. @Test
  73. fun `IrcClientImpl sends password first, when present`() {
  74. runBlocking {
  75. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  76. client.socketFactory = mockSocketFactory
  77. readLineChannel.close()
  78. client.connect()
  79. with(inOrder(mockSocket).verify(mockSocket)) {
  80. sendLine("CAP LS 302")
  81. sendLine("PASS :$PASSWORD")
  82. sendLine("NICK :$NICK")
  83. }
  84. }
  85. }
  86. @Test
  87. fun `IrcClientImpl sends events to provided event handler`() {
  88. runBlocking {
  89. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  90. client.socketFactory = mockSocketFactory
  91. client.eventHandler = mockEventHandler
  92. launch {
  93. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  94. readLineChannel.close()
  95. }
  96. client.connect()
  97. verify(mockEventHandler).processEvent(client, ServerWelcome("acidBurn"))
  98. }
  99. }
  100. @Test
  101. fun `IrcClientImpl removes old event handlers when new one is added`() {
  102. runBlocking {
  103. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  104. client.socketFactory = mockSocketFactory
  105. client.eventHandler = mockEventHandler
  106. client.eventHandler = mock()
  107. launch {
  108. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  109. readLineChannel.close()
  110. }
  111. client.connect()
  112. verify(mockEventHandler, never()).processEvent(client, ServerWelcome("acidBurn"))
  113. }
  114. }
  115. @Test
  116. fun `IrcClientImpl removes old event handlers when it is set to null`() {
  117. runBlocking {
  118. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  119. client.socketFactory = mockSocketFactory
  120. client.eventHandler = mockEventHandler
  121. client.eventHandler = null
  122. launch {
  123. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  124. readLineChannel.close()
  125. }
  126. client.connect()
  127. verify(mockEventHandler, never()).processEvent(client, ServerWelcome("acidBurn"))
  128. }
  129. }
  130. @Test
  131. fun `IrcClient gets case mapping from server features`() {
  132. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  133. client.serverState.features[ServerFeature.ServerCaseMapping] = CaseMapping.RfcStrict
  134. assertEquals(CaseMapping.RfcStrict, client.caseMapping)
  135. }
  136. @Test
  137. fun `IrcClient indicates if user is local user or not`() {
  138. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  139. client.serverState.localNickname = "[acidBurn]"
  140. assertTrue(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
  141. assertFalse(client.isLocalUser(User("acid-Burn", "libby", "root.localhost")))
  142. }
  143. @Test
  144. fun `IrcClient uses current case mapping to check local user`() {
  145. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  146. client.serverState.localNickname = "[acidBurn]"
  147. client.serverState.features[ServerFeature.ServerCaseMapping] = CaseMapping.Ascii
  148. assertFalse(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
  149. }
  150. }