package org.terst.nav.ui import androidx.arch.core.executor.testing.InstantTaskExecutorRule 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.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test import org.terst.nav.sensors.WindData import org.terst.nav.ui.MainViewModel @OptIn(ExperimentalCoroutinesApi::class) class MainViewModelWindTest { @get:Rule val instantTask = InstantTaskExecutorRule() private val dispatcher = UnconfinedTestDispatcher() @Before fun setUp() { Dispatchers.setMain(dispatcher) } @After fun tearDown() { Dispatchers.resetMain() } @Test fun `addGpsPoint uses zero wind when no wind update received`() = runTest { val vm = MainViewModel() vm.startTrack() vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) val pt = vm.trackPoints.value.first() assertEquals(0.0, pt.windSpeedKnots, 0.001) assertEquals(0.0, pt.windAngleDeg, 0.001) assertEquals(false, pt.isTrueWind) } @Test fun `addGpsPoint uses latest wind data after updateWind`() = runTest { val vm = MainViewModel() vm.updateWind(WindData(windAngle = 45.0, windSpeed = 15.5, isTrueWind = true, timestampMs = 1000L)) vm.startTrack() vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) val pt = vm.trackPoints.value.first() assertEquals(15.5, pt.windSpeedKnots, 0.001) assertEquals(45.0, pt.windAngleDeg, 0.001) assertEquals(true, pt.isTrueWind) } @Test fun `addGpsPoint reflects wind update between fixes`() = runTest { val vm = MainViewModel() vm.startTrack() vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) vm.updateWind(WindData(windAngle = 180.0, windSpeed = 8.0, isTrueWind = false, timestampMs = 2000L)) vm.addGpsPoint(37.1, -122.0, 5.0, 90.0) val pts = vm.trackPoints.value assertEquals(0.0, pts[0].windSpeedKnots, 0.001) assertEquals(8.0, pts[1].windSpeedKnots, 0.001) } }