summaryrefslogtreecommitdiff
path: root/test-runner/src/test/kotlin/org/terst/nav/nmea/NmeaParserTest.kt
blob: e43b7ab9d123652ab6695e6dc9d0d64b942716d9 (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
package org.terst.nav.nmea

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

class NmeaParserTest {

    private lateinit var parser: NmeaParser

    @Before
    fun setUp() {
        parser = NmeaParser()
    }

    // $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
    // lat: 48 + 7.038/60 = 48.1173°N, lon: 11 + 31.000/60 = 11.51667°E
    // SOG 22.4 kn, COG 84.4°

    @Test
    fun `valid RMC sentence parses latitude and longitude`() {
        val sentence = "\$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertEquals(48.1173, pos!!.latitude, 0.0001)
        assertEquals(11.51667, pos.longitude, 0.0001)
    }

    @Test
    fun `valid RMC sentence parses SOG and COG`() {
        val sentence = "\$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertEquals(22.4, pos!!.sog, 0.001)
        assertEquals(84.4, pos.cog, 0.001)
    }

    @Test
    fun `void status V returns null`() {
        val sentence = "\$GPRMC,123519,V,4807.038,N,01131.000,E,,,230394,003.1,W"
        assertNull(parser.parseRmc(sentence))
    }

    @Test
    fun `malformed sentence with too few fields returns null`() {
        assertNull(parser.parseRmc("\$GPRMC,123519,A"))
    }

    @Test
    fun `empty string returns null`() {
        assertNull(parser.parseRmc(""))
    }

    @Test
    fun `non-NMEA string returns null`() {
        assertNull(parser.parseRmc("NOT_NMEA_DATA"))
    }

    @Test
    fun `south latitude is negative`() {
        // lat: -(42 + 50.5589/60) = -42.84265
        val sentence = "\$GPRMC,092204.999,A,4250.5589,S,14718.5084,E,0.00,89.68,211200,,"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertTrue("South latitude must be negative", pos!!.latitude < 0)
        assertEquals(-42.84265, pos.latitude, 0.0001)
    }

    @Test
    fun `west longitude is negative`() {
        // lon: -(11 + 31.000/60) = -11.51667
        val sentence = "\$GPRMC,123519,A,4807.038,N,01131.000,W,022.4,084.4,230394,003.1,E"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertTrue("West longitude must be negative", pos!!.longitude < 0)
        assertEquals(-11.51667, pos.longitude, 0.0001)
    }

    @Test
    fun `SOG and COG parse with decimal precision`() {
        // lon: -(118 + 1.5678/60) = -118.02613, lat: 33 + 52.1234/60 = 33.86872
        val sentence = "\$GPRMC,093456,A,3352.1234,N,11801.5678,W,12.345,270.5,140326,,"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertEquals(12.345, pos!!.sog, 0.0001)
        assertEquals(270.5, pos.cog, 0.0001)
    }

    @Test
    fun `empty SOG and COG fields default to zero`() {
        val sentence = "\$GPRMC,123519,A,4807.038,N,01131.000,E,,,230394,003.1,W"
        val pos = parser.parseRmc(sentence)
        assertNotNull(pos)
        assertEquals(0.0, pos!!.sog, 0.001)
        assertEquals(0.0, pos.cog, 0.001)
    }

    @Test
    fun `non-RMC sentence returns null`() {
        val sentence = "\$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,"
        assertNull(parser.parseRmc(sentence))
    }
}