summaryrefslogtreecommitdiff
path: root/test-runner/src/test/kotlin/org/terst/nav/gps/GpsProviderTest.kt
blob: 4a03387ac842cf4121cc2bd3023da9e24eb2f85b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package org.terst.nav.gps

import org.junit.Assert.*
import org.junit.Before
import org.junit.Test

// ── Fake implementation (no Android dependencies) ────────────────────────────

class FakeGpsProvider : GpsProvider {
    var currentPosition: GpsPosition? = null
    private val listeners = mutableListOf<GpsListener>()
    var started = false

    override fun start() { started = true }
    override fun stop() { started = false }
    override val position: GpsPosition? get() = currentPosition
    override fun addListener(listener: GpsListener) { listeners.add(listener) }
    override fun removeListener(listener: GpsListener) { listeners.remove(listener) }

    fun simulatePosition(pos: GpsPosition) {
        currentPosition = pos
        listeners.forEach { it.onPositionUpdate(pos) }
    }

    fun simulateFixLost() { listeners.forEach { it.onFixLost() } }
}

// ── Test helpers ─────────────────────────────────────────────────────────────

private fun makePosition(lat: Double = 41.0, lon: Double = -71.0, sog: Double = 5.0) =
    GpsPosition(lat, lon, sog, cog = 180.0, timestampMs = 1_000L)

private class RecordingListener : GpsListener {
    val positions = mutableListOf<GpsPosition>()
    var fixLostCount = 0

    override fun onPositionUpdate(position: GpsPosition) { positions.add(position) }
    override fun onFixLost() { fixLostCount++ }
}

// ── Tests ─────────────────────────────────────────────────────────────────────

class GpsProviderTest {

    private lateinit var provider: FakeGpsProvider

    @Before
    fun setUp() {
        provider = FakeGpsProvider()
    }

    @Test
    fun `start sets started to true`() {
        provider.start()
        assertTrue(provider.started)
    }

    @Test
    fun `stop sets started to false`() {
        provider.start()
        provider.stop()
        assertFalse(provider.started)
    }

    @Test
    fun `listener receives position update`() {
        val listener = RecordingListener()
        provider.addListener(listener)
        val pos = makePosition()
        provider.simulatePosition(pos)
        assertEquals(1, listener.positions.size)
        assertEquals(pos, listener.positions[0])
    }

    @Test
    fun `listener notified of fix lost`() {
        val listener = RecordingListener()
        provider.addListener(listener)
        provider.simulateFixLost()
        assertEquals(1, listener.fixLostCount)
    }

    @Test
    fun `multiple listeners all receive position update`() {
        val l1 = RecordingListener()
        val l2 = RecordingListener()
        val l3 = RecordingListener()
        provider.addListener(l1)
        provider.addListener(l2)
        provider.addListener(l3)
        provider.simulatePosition(makePosition())
        assertEquals(1, l1.positions.size)
        assertEquals(1, l2.positions.size)
        assertEquals(1, l3.positions.size)
    }

    @Test
    fun `multiple listeners all notified of fix lost`() {
        val l1 = RecordingListener()
        val l2 = RecordingListener()
        provider.addListener(l1)
        provider.addListener(l2)
        provider.simulateFixLost()
        assertEquals(1, l1.fixLostCount)
        assertEquals(1, l2.fixLostCount)
    }

    @Test
    fun `removing listener stops notifications`() {
        val listener = RecordingListener()
        provider.addListener(listener)
        provider.removeListener(listener)
        provider.simulatePosition(makePosition())
        provider.simulateFixLost()
        assertEquals(0, listener.positions.size)
        assertEquals(0, listener.fixLostCount)
    }

    @Test
    fun `position property reflects last simulated position`() {
        assertNull(provider.position)
        val pos = makePosition(lat = 42.5, lon = -70.0)
        provider.simulatePosition(pos)
        assertEquals(pos, provider.position)
    }

    @Test
    fun `SOG conversion sanity check - 1 mps is approximately 1_94384 knots`() {
        // 1 m/s * 1.94384 = 1.94384 knots — validate constant used in DeviceGpsProvider
        val knots = 1.0 * 1.94384
        assertEquals(1.94384, knots, 0.00001)
    }
}