package org.terst.nav.track import org.junit.Assert.* import org.junit.Before import org.junit.Test class TrackStatsTest { private lateinit var repo: TrackRepository private fun pt(lat: Double, lon: Double, sog: Double = 5.0, ts: Long = 0L) = TrackPoint(lat, lon, sog, 0.0, 0.0, 0.0, false, ts) @Before fun setup() { repo = TrackRepository() repo.startTrack() } @Test fun `computeStats returns null for single point`() { repo.addPoint(pt(41.0, -71.0, ts = 0)) assertNull(repo.computeStats()) } @Test fun `computeStats returns null when not recording and no points`() { repo.stopTrack() assertNull(repo.computeStats()) } @Test fun `haversineNm one degree of latitude is approximately 60 nm`() { val d = TrackRepository.haversineNm(0.0, 0.0, 1.0, 0.0) assertEquals(60.0, d, 0.5) } @Test fun `haversineNm zero distance returns zero`() { assertEquals(0.0, TrackRepository.haversineNm(41.0, -71.0, 41.0, -71.0), 1e-9) } @Test fun `computeStats distance accumulates across legs`() { repo.addPoint(pt(0.0, 0.0, ts = 0)) repo.addPoint(pt(1.0, 0.0, ts = 3_600_000)) // ~60 nm north repo.addPoint(pt(1.0, 1.0, ts = 7_200_000)) // ~60 nm east at 1° lat val stats = repo.computeStats()!! assertTrue("Expected ~120 nm, got ${stats.distanceNm}", stats.distanceNm > 100.0) } @Test fun `computeStats duration is last minus first timestamp`() { repo.addPoint(pt(0.0, 0.0, ts = 1_000)) repo.addPoint(pt(1.0, 0.0, ts = 3_601_000)) val stats = repo.computeStats()!! assertEquals(3_600_000L, stats.durationMs) } @Test fun `computeStats avgSog is mean of all point sogs`() { repo.addPoint(pt(0.0, 0.0, sog = 4.0, ts = 0)) repo.addPoint(pt(0.0, 0.1, sog = 6.0, ts = 1000)) val stats = repo.computeStats()!! assertEquals(5.0, stats.avgSogKnots, 0.001) } @Test fun `durationFormatted shows m_ss below one hour`() { val stats = TrackStats(1.0, 65_000L, 5.0) // 1 min 5 sec assertEquals("1:05", stats.durationFormatted) } @Test fun `durationFormatted shows h_mm_ss above one hour`() { val stats = TrackStats(1.0, 3_661_000L, 5.0) // 1h 1m 1s assertEquals("1:01:01", stats.durationFormatted) } }