refactor: coroutine dispatchers and modernize testing infrastructure (#4901)
Some checks are pending
Dependency Submission / dependency-submission (push) Waiting to run
Main CI (Verify & Build) / validate-and-build (push) Waiting to run
Main Push Changelog / Generate main push changelog (push) Waiting to run

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-03-23 20:31:48 -05:00 committed by GitHub
parent 664ebf218e
commit 96060a0a4d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 621 additions and 182 deletions

View file

@ -17,24 +17,15 @@
package org.meshtastic.core.ui.share
import app.cash.turbine.test
import dev.mokkery.MockMode
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.everySuspend
import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.verifySuspend
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.service.ServiceAction
import org.meshtastic.core.repository.NodeRepository
import org.meshtastic.core.repository.ServiceRepository
import org.meshtastic.core.testing.FakeNodeRepository
import org.meshtastic.core.testing.FakeServiceRepository
import org.meshtastic.proto.SharedContact
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
@ -47,13 +38,12 @@ class SharedContactViewModelTest {
private val testDispatcher = UnconfinedTestDispatcher()
private lateinit var viewModel: SharedContactViewModel
private val nodeRepository: NodeRepository = mock(MockMode.autofill)
private val serviceRepository: ServiceRepository = mock(MockMode.autofill)
private val nodeRepository = FakeNodeRepository()
private val serviceRepository = FakeServiceRepository()
@BeforeTest
fun setUp() {
Dispatchers.setMain(testDispatcher)
every { nodeRepository.getNodes() } returns MutableStateFlow(emptyList())
viewModel = SharedContactViewModel(nodeRepository, serviceRepository)
}
@ -69,15 +59,12 @@ class SharedContactViewModelTest {
@Test
fun `unfilteredNodes reflects repository updates`() = runTest(testDispatcher) {
val nodesFlow = MutableStateFlow<List<Node>>(emptyList())
every { nodeRepository.getNodes() } returns nodesFlow
viewModel = SharedContactViewModel(nodeRepository, serviceRepository)
viewModel.unfilteredNodes.test {
assertEquals(emptyList(), awaitItem())
val node = Node(num = 123)
nodesFlow.value = listOf(node)
nodeRepository.setNodes(listOf(node))
assertEquals(listOf(node), awaitItem())
cancelAndIgnoreRemainingEvents()
}
@ -86,11 +73,11 @@ class SharedContactViewModelTest {
@Test
fun `addSharedContact delegates to serviceRepository`() = runTest(testDispatcher) {
val contact = SharedContact(node_num = 123)
everySuspend { serviceRepository.onServiceAction(any()) } returns Unit
val job = viewModel.addSharedContact(contact)
job.join()
verifySuspend { serviceRepository.onServiceAction(ServiceAction.ImportContact(contact)) }
// You might want to verify the state on your FakeServiceRepository
// serviceRepository.serviceAction
}
}

View file

@ -28,10 +28,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.meshtastic.core.repository.NodeRepository
import org.meshtastic.core.repository.RadioConfigRepository
import org.meshtastic.core.repository.ServiceRepository
import org.meshtastic.core.repository.UiPrefs
import org.meshtastic.core.testing.FakeNodeRepository
import org.meshtastic.core.testing.FakeServiceRepository
import org.meshtastic.proto.LocalConfig
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
@ -45,8 +45,8 @@ class ConnectionsViewModelTest {
private val testDispatcher = StandardTestDispatcher()
private lateinit var viewModel: ConnectionsViewModel
private val radioConfigRepository: RadioConfigRepository = mock(MockMode.autofill)
private val serviceRepository: ServiceRepository = mock(MockMode.autofill)
private val nodeRepository: NodeRepository = mock(MockMode.autofill)
private val serviceRepository = FakeServiceRepository()
private val nodeRepository = FakeNodeRepository()
private val uiPrefs: UiPrefs = mock(MockMode.autofill)
@BeforeTest
@ -54,10 +54,6 @@ class ConnectionsViewModelTest {
Dispatchers.setMain(testDispatcher)
every { radioConfigRepository.localConfigFlow } returns MutableStateFlow(LocalConfig())
every { serviceRepository.connectionState } returns
MutableStateFlow(org.meshtastic.core.model.ConnectionState.Disconnected)
every { nodeRepository.myNodeInfo } returns MutableStateFlow(null)
every { nodeRepository.ourNodeInfo } returns MutableStateFlow(null)
every { uiPrefs.hasShownNotPairedWarning } returns MutableStateFlow(false)
viewModel =