mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
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
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:
parent
664ebf218e
commit
96060a0a4d
36 changed files with 621 additions and 182 deletions
|
|
@ -23,7 +23,6 @@ import co.touchlab.kermit.Logger
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
|
@ -220,12 +219,13 @@ class DebugViewModel(
|
|||
private val nodeRepository: NodeRepository,
|
||||
private val meshLogPrefs: MeshLogPrefs,
|
||||
private val alertManager: AlertManager,
|
||||
private val dispatchers: org.meshtastic.core.di.CoroutineDispatchers,
|
||||
) : ViewModel() {
|
||||
|
||||
val meshLog: StateFlow<ImmutableList<UiMeshLog>> =
|
||||
meshLogRepository
|
||||
.getAllLogs()
|
||||
.mapLatest { logs -> withContext(Dispatchers.Default) { toUiState(logs) } }
|
||||
.mapLatest { logs -> withContext(dispatchers.default) { toUiState(logs) } }
|
||||
.stateInWhileSubscribed(initialValue = persistentListOf())
|
||||
|
||||
private val _retentionDays = MutableStateFlow(meshLogPrefs.retentionDays.value)
|
||||
|
|
|
|||
|
|
@ -16,27 +16,44 @@
|
|||
*/
|
||||
package org.meshtastic.feature.settings.debugging
|
||||
|
||||
import dev.mokkery.MockMode
|
||||
import dev.mokkery.matcher.any
|
||||
import dev.mokkery.mock
|
||||
import dev.mokkery.verify
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.testing.FakeMeshLogPrefs
|
||||
import org.meshtastic.core.testing.FakeMeshLogRepository
|
||||
import org.meshtastic.core.testing.FakeNodeRepository
|
||||
import org.meshtastic.core.ui.util.AlertManager
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class DebugViewModelTest {
|
||||
/*
|
||||
|
||||
private val meshLogRepository = FakeMeshLogRepository()
|
||||
private val nodeRepository = FakeNodeRepository()
|
||||
private val meshLogPrefs = FakeMeshLogPrefs()
|
||||
private val alertManager: AlertManager = mock(MockMode.autofill)
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
|
||||
private val dispatchers = CoroutineDispatchers(testDispatcher, testDispatcher, testDispatcher)
|
||||
|
||||
private lateinit var viewModel: DebugViewModel
|
||||
|
||||
@Before
|
||||
@BeforeTest
|
||||
fun setUp() {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
|
||||
every { meshLogRepository.getAllLogs() } returns flowOf(emptyList())
|
||||
every { nodeRepository.myNodeInfo } returns MutableStateFlow(null)
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(emptyMap())
|
||||
every { meshLogPrefs.retentionDays.value } returns 7
|
||||
every { meshLogPrefs.loggingEnabled.value } returns true
|
||||
meshLogPrefs.setRetentionDays(7)
|
||||
meshLogPrefs.setLoggingEnabled(true)
|
||||
|
||||
viewModel =
|
||||
DebugViewModel(
|
||||
|
|
@ -44,10 +61,11 @@ class DebugViewModelTest {
|
|||
nodeRepository = nodeRepository,
|
||||
meshLogPrefs = meshLogPrefs,
|
||||
alertManager = alertManager,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
@AfterTest
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
|
@ -56,17 +74,18 @@ class DebugViewModelTest {
|
|||
fun `setRetentionDays updates prefs and deletes old logs`() = runTest {
|
||||
viewModel.setRetentionDays(14)
|
||||
|
||||
verify { meshLogPrefs.setRetentionDays(14) }
|
||||
verifySuspend { meshLogRepository.deleteLogsOlderThan(14) }
|
||||
meshLogPrefs.retentionDays.value shouldBe 14
|
||||
meshLogRepository.deleteLogsOlderThanCalledDays shouldBe 14
|
||||
viewModel.retentionDays.value shouldBe 14
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setLoggingEnabled false deletes all logs`() = runTest {
|
||||
meshLogRepository.insert(org.meshtastic.core.model.MeshLog("123", "type", 1L, "raw"))
|
||||
viewModel.setLoggingEnabled(false)
|
||||
|
||||
verify { meshLogPrefs.setLoggingEnabled(false) }
|
||||
verifySuspend { meshLogRepository.deleteAll() }
|
||||
meshLogPrefs.loggingEnabled.value shouldBe false
|
||||
meshLogRepository.currentLogs shouldBe emptyList()
|
||||
viewModel.loggingEnabled.value shouldBe false
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +110,4 @@ class DebugViewModelTest {
|
|||
viewModel.requestDeleteAllLogs()
|
||||
verify { alertManager.showAlert(titleRes = any(), messageRes = any(), onConfirm = any()) }
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ import org.meshtastic.core.repository.HomoglyphPrefs
|
|||
import org.meshtastic.core.repository.LocationRepository
|
||||
import org.meshtastic.core.repository.LocationService
|
||||
import org.meshtastic.core.repository.MapConsentPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
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.feature.settings.navigation.ConfigRoute
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.ChannelSettings
|
||||
|
|
@ -82,7 +82,7 @@ class RadioConfigViewModelTest {
|
|||
private val radioConfigRepository: RadioConfigRepository = mock(MockMode.autofill)
|
||||
private val packetRepository: PacketRepository = mock(MockMode.autofill)
|
||||
private val serviceRepository: ServiceRepository = mock(MockMode.autofill)
|
||||
private val nodeRepository: NodeRepository = mock(MockMode.autofill)
|
||||
private val nodeRepository = FakeNodeRepository()
|
||||
private val locationRepository: LocationRepository = mock(MockMode.autofill)
|
||||
private val mapConsentPrefs: MapConsentPrefs = mock(MockMode.autofill)
|
||||
private val analyticsPrefs: AnalyticsPrefs = mock(MockMode.autofill)
|
||||
|
|
@ -107,8 +107,6 @@ class RadioConfigViewModelTest {
|
|||
fun setUp() {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(emptyMap())
|
||||
every { nodeRepository.myNodeInfo } returns MutableStateFlow(null)
|
||||
every { radioConfigRepository.deviceProfileFlow } returns MutableStateFlow(DeviceProfile())
|
||||
every { radioConfigRepository.localConfigFlow } returns MutableStateFlow(LocalConfig())
|
||||
every { radioConfigRepository.channelSetFlow } returns MutableStateFlow(ChannelSet())
|
||||
|
|
@ -153,7 +151,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setConfig calls useCase`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
val config = Config(device = Config.DeviceConfig(role = Config.DeviceConfig.Role.ROUTER))
|
||||
|
|
@ -191,7 +189,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `processPacketResponse updates state on metadata result`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
|
||||
val packet = MeshPacket()
|
||||
val metadata = DeviceMetadata(firmware_version = "3.0.0")
|
||||
|
|
@ -214,7 +212,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `updateChannels calls useCase for each changed channel`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
val old = listOf(ChannelSettings(name = "Old"))
|
||||
|
|
@ -231,7 +229,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setResponseStateLoading for REBOOT calls useCase after packet response`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
|
||||
val packetFlow = MutableSharedFlow<MeshPacket>()
|
||||
every { serviceRepository.meshPacketFlow } returns packetFlow
|
||||
|
|
@ -252,7 +250,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setResponseStateLoading for FACTORY_RESET calls useCase after packet response`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
|
||||
val packetFlow = MutableSharedFlow<MeshPacket>()
|
||||
every { serviceRepository.meshPacketFlow } returns packetFlow
|
||||
|
|
@ -283,7 +281,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setOwner calls useCase`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
val user = User(long_name = "Test User")
|
||||
|
|
@ -297,7 +295,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setRingtone calls useCase`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
everySuspend { radioConfigUseCase.setRingtone(any(), any()) } returns Unit
|
||||
|
|
@ -311,7 +309,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `setCannedMessages calls useCase`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
everySuspend { radioConfigUseCase.setCannedMessages(any(), any()) } returns Unit
|
||||
|
|
@ -341,7 +339,7 @@ class RadioConfigViewModelTest {
|
|||
@Test
|
||||
fun `registerRequestId timeout clears request and sets error`() = runTest {
|
||||
val node = Node(num = 123, user = User(id = "!123"))
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(mapOf(123 to node))
|
||||
nodeRepository.setNodes(listOf(node))
|
||||
viewModel = createViewModel()
|
||||
|
||||
everySuspend { radioConfigUseCase.getOwner(any()) } returns 42
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue