summaryrefslogtreecommitdiff
path: root/android-app/app/src/test/kotlin/com/example
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/test/kotlin/com/example')
-rw-r--r--android-app/app/src/test/kotlin/com/example/androidapp/gps/LocationServiceTest.kt90
1 files changed, 90 insertions, 0 deletions
diff --git a/android-app/app/src/test/kotlin/com/example/androidapp/gps/LocationServiceTest.kt b/android-app/app/src/test/kotlin/com/example/androidapp/gps/LocationServiceTest.kt
index 237004b..4eb9898 100644
--- a/android-app/app/src/test/kotlin/com/example/androidapp/gps/LocationServiceTest.kt
+++ b/android-app/app/src/test/kotlin/com/example/androidapp/gps/LocationServiceTest.kt
@@ -119,15 +119,20 @@ class LocationServiceTest {
private fun fusionService(
nmeaStalenessThresholdMs: Long = 5_000L,
+ nmeaExtendedThresholdMs: Long = 10_000L,
clockMs: () -> Long = System::currentTimeMillis
) = LocationService(
nmeaStalenessThresholdMs = nmeaStalenessThresholdMs,
+ nmeaExtendedThresholdMs = nmeaExtendedThresholdMs,
clockMs = clockMs
)
private fun pos(lat: Double, lon: Double, timestampMs: Long) =
GpsPosition(lat, lon, sog = 0.0, cog = 0.0, timestampMs = timestampMs)
+ private fun posWithAccuracy(lat: Double, lon: Double, timestampMs: Long, accuracyMeters: Double) =
+ GpsPosition(lat, lon, sog = 0.0, cog = 0.0, timestampMs = timestampMs, accuracyMeters = accuracyMeters)
+
@Test
fun noGpsData_bestPositionNullAndSourceNone() = runBlocking {
val svc = fusionService()
@@ -203,6 +208,91 @@ class LocationServiceTest {
assertEquals(GpsSource.NMEA, svc.activeGpsSource.first())
}
+ // ── fix-quality (accuracy) tie-breaking ──────────────────────────────────
+
+ @Test
+ fun marginallyStaleNmea_betterAccuracy_preferredOverAndroid() = runBlocking {
+ // NMEA is 7 s old (> primary 5 s, ≤ extended 10 s) but has accuracy 3 m vs Android 15 m.
+ val nmeaTime = 0L
+ val now = 7_000L
+ val svc = fusionService(
+ nmeaStalenessThresholdMs = 5_000L,
+ nmeaExtendedThresholdMs = 10_000L,
+ clockMs = { now }
+ )
+
+ val nmeaFix = posWithAccuracy(41.0, -71.0, nmeaTime, accuracyMeters = 3.0)
+ val androidFix = posWithAccuracy(42.0, -72.0, now, accuracyMeters = 15.0)
+
+ svc.updateNmeaGps(nmeaFix)
+ svc.updateAndroidGps(androidFix)
+
+ assertEquals(GpsSource.NMEA, svc.activeGpsSource.first())
+ assertEquals(nmeaFix, svc.bestPosition.first())
+ }
+
+ @Test
+ fun marginallyStaleNmea_worseAccuracy_fallsBackToAndroid() = runBlocking {
+ // NMEA is 7 s old with accuracy 15 m; Android has accuracy 3 m → Android wins.
+ val nmeaTime = 0L
+ val now = 7_000L
+ val svc = fusionService(
+ nmeaStalenessThresholdMs = 5_000L,
+ nmeaExtendedThresholdMs = 10_000L,
+ clockMs = { now }
+ )
+
+ val nmeaFix = posWithAccuracy(41.0, -71.0, nmeaTime, accuracyMeters = 15.0)
+ val androidFix = posWithAccuracy(42.0, -72.0, now, accuracyMeters = 3.0)
+
+ svc.updateNmeaGps(nmeaFix)
+ svc.updateAndroidGps(androidFix)
+
+ assertEquals(GpsSource.ANDROID, svc.activeGpsSource.first())
+ assertEquals(androidFix, svc.bestPosition.first())
+ }
+
+ @Test
+ fun marginallyStaleNmea_noAccuracyData_fallsBackToAndroid() = runBlocking {
+ // Neither source has accuracy metadata — conservative: prefer Android.
+ val nmeaTime = 0L
+ val now = 7_000L
+ val svc = fusionService(
+ nmeaStalenessThresholdMs = 5_000L,
+ nmeaExtendedThresholdMs = 10_000L,
+ clockMs = { now }
+ )
+
+ val nmeaFix = pos(41.0, -71.0, nmeaTime)
+ val androidFix = pos(42.0, -72.0, now)
+
+ svc.updateNmeaGps(nmeaFix)
+ svc.updateAndroidGps(androidFix)
+
+ assertEquals(GpsSource.ANDROID, svc.activeGpsSource.first())
+ }
+
+ @Test
+ fun veryStaleNmea_beyondExtendedThreshold_androidPreferred() = runBlocking {
+ // NMEA is 15 s old (beyond extended 10 s); Android wins even if NMEA has better accuracy.
+ val nmeaTime = 0L
+ val now = 15_000L
+ val svc = fusionService(
+ nmeaStalenessThresholdMs = 5_000L,
+ nmeaExtendedThresholdMs = 10_000L,
+ clockMs = { now }
+ )
+
+ val nmeaFix = posWithAccuracy(41.0, -71.0, nmeaTime, accuracyMeters = 2.0)
+ val androidFix = posWithAccuracy(42.0, -72.0, now, accuracyMeters = 20.0)
+
+ svc.updateNmeaGps(nmeaFix)
+ svc.updateAndroidGps(androidFix)
+
+ assertEquals(GpsSource.ANDROID, svc.activeGpsSource.first())
+ assertEquals(androidFix, svc.bestPosition.first())
+ }
+
@Test
fun nmeaRecovery_switchesBackFromAndroid() = runBlocking {
var now = 0L