package com.example.androidapp.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-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)) } @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`() { 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 `GNRMC talker ID is also accepted`() { val sentence = "\$GNRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W" val pos = parser.parseRmc(sentence) assertNotNull(pos) assertEquals(48.1173, pos!!.latitude, 0.0001) } }