diff --git a/app/src/main/java/com/bitchat/android/ui/CommandProcessor.kt b/app/src/main/java/com/bitchat/android/ui/CommandProcessor.kt index 703a7f13..4e426454 100644 --- a/app/src/main/java/com/bitchat/android/ui/CommandProcessor.kt +++ b/app/src/main/java/com/bitchat/android/ui/CommandProcessor.kt @@ -2,7 +2,7 @@ package com.bitchat.android.ui import com.bitchat.android.mesh.BluetoothMeshService import com.bitchat.android.model.BitchatMessage -import java.util.* +import java.util.Date /** * Handles processing of IRC-style commands @@ -33,8 +33,7 @@ class CommandProcessor( if (!command.startsWith("/")) return false val parts = command.split(" ") - val cmd = parts.first() - + val cmd = parts.first().lowercase() when (cmd) { "/j", "/join" -> handleJoinCommand(parts, myPeerID) "/m", "/msg" -> handleMessageCommand(parts, meshService) diff --git a/app/src/test/java/com/bitchat/android/ui/CommandProcessorTest.kt b/app/src/test/java/com/bitchat/android/ui/CommandProcessorTest.kt new file mode 100644 index 00000000..5d838893 --- /dev/null +++ b/app/src/test/java/com/bitchat/android/ui/CommandProcessorTest.kt @@ -0,0 +1,114 @@ +package com.bitchat.android.ui + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import com.bitchat.android.mesh.BluetoothMeshService +import com.bitchat.android.model.BitchatMessage +import junit.framework.TestCase.assertEquals +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.test.StandardTestDispatcher +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.Spy +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.refEq +import org.mockito.kotlin.verify +import org.robolectric.RobolectricTestRunner +import java.util.Date + +@RunWith(RobolectricTestRunner::class) +class CommandProcessorTest() { + private val context: Context = ApplicationProvider.getApplicationContext() + private val meshService = BluetoothMeshService(context = context) + private val chatState = ChatState() + private lateinit var commandProcessor: CommandProcessor + @Spy + val messageManager: MessageManager = Mockito.spy(MessageManager(state = chatState)) + + @Spy + val channelManager: ChannelManager = Mockito.spy( + ChannelManager( + state = chatState, + messageManager = messageManager, + dataManager = DataManager(context = context), + coroutineScope = CoroutineScope(StandardTestDispatcher()) + ) + ) + + @Before + fun setup() { + commandProcessor = CommandProcessor( + state = chatState, + messageManager = messageManager, + channelManager = channelManager, + privateChatManager = PrivateChatManager( + state = chatState, + messageManager = messageManager, + dataManager = DataManager(context = context), + noiseSessionDelegate = mock() + ) + ) + } + + @Test + fun `when using lower case join command, user is correctly added to channel`() { + val channel = "channel-1" + val expectedMessage = BitchatMessage( + sender = "system", + content = "joined channel #$channel", + timestamp = Date(), + isRelay = false + ) + + val result = commandProcessor.processCommand( + command = "/j $channel", + meshService = meshService, + myPeerID = "peer-id", + onSendMessage = { a, b, c -> { } }, + viewModel = null + ) + + assertEquals(result, true) + verify(messageManager).addMessage(refEq(expectedMessage, "timestamp", "id")) + } + + @Test + fun `when using upper case join command, user is correctly added to channel`() { + val channel = "channel-1" + val expectedMessage = BitchatMessage( + sender = "system", + content = "joined channel #$channel", + timestamp = Date(), + isRelay = false + ) + + val result = commandProcessor.processCommand( + command = "/JOIN $channel", + meshService = meshService, + myPeerID = "peer-id", + onSendMessage = { a, b, c -> { } }, + viewModel = null + ) + + assertEquals(result, true) + verify(messageManager).addMessage(refEq(expectedMessage, "timestamp", "id")) + } + + @Test + fun `when unknown command lower case is given, channel is not joined`() { + val channel = "channel-1" + + val result = commandProcessor.processCommand( + command = "/wtfjoin $channel", meshService = meshService, myPeerID = "peer-id", + onSendMessage = { a, b, c -> { } }, viewModel = null + ) + + assertEquals(result, true) + verify(channelManager, never()).joinChannel(eq("#$channel"), anyOrNull(), eq("peer-id")) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7e3a5fba..e6dda224 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,6 +52,7 @@ espresso = "3.6.1" mockito-kotlin = "4.1.0" mockito-inline = "4.1.0" roboelectric = "4.15" +kotlinx-coroutines-test = "1.6" [libraries] # AndroidX Core @@ -114,6 +115,7 @@ androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-mani mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockito-kotlin" } mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito-inline" } roboelectric = { module = "org.robolectric:robolectric", version.ref = "roboelectric"} +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test"} [plugins] android-application = { id = "com.android.application", version.ref = "agp" } @@ -149,7 +151,8 @@ testing = [ "androidx-test-espresso-core", "mockito-kotlin", "mockito-inline", - "roboelectric" + "roboelectric", + "kotlinx-coroutines-test" ] compose-testing = [