You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IrcClientTest.kt 6.6KB

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