Skip to content

Commit e4c6422

Browse files
caveman99ndoo
andcommitted
Add NMEA sentence regression tests
Covers checksum computation from the $ delimiter for both printWPL overloads and printGGA, zero-sized buffers, and truncated buffers down to one byte. Co-Authored-By: Andrew Yong <me@ndoo.sg>
1 parent b9c4542 commit e4c6422

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

test/test_nmea_wpl/test_main.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include "GeoCoord.h"
2+
#include "NMEAWPL.h"
3+
#include "TestUtil.h"
4+
#include "mesh-pb-constants.h"
5+
#include <cstdint>
6+
#include <cstring>
7+
#include <unity.h>
8+
9+
void setUp(void) {}
10+
void tearDown(void) {}
11+
12+
static meshtastic_PositionLite makePositionLite()
13+
{
14+
meshtastic_PositionLite pos = meshtastic_PositionLite_init_default;
15+
pos.latitude_i = 472852133;
16+
pos.longitude_i = 85652500;
17+
pos.altitude = 400;
18+
pos.time = 42;
19+
return pos;
20+
}
21+
22+
static meshtastic_Position makePosition()
23+
{
24+
meshtastic_Position pos = meshtastic_Position_init_default;
25+
pos.has_latitude_i = true;
26+
pos.latitude_i = 472852133;
27+
pos.has_longitude_i = true;
28+
pos.longitude_i = 85652500;
29+
pos.has_altitude = true;
30+
pos.altitude = 400;
31+
pos.timestamp = 43;
32+
return pos;
33+
}
34+
35+
static uint32_t expectedChecksum(const char *sentence)
36+
{
37+
uint32_t chk = 0;
38+
const char *c = strchr(sentence, '$');
39+
TEST_ASSERT_NOT_NULL(c);
40+
for (c++; *c && *c != '*'; c++)
41+
chk ^= (uint8_t)*c;
42+
return chk;
43+
}
44+
45+
static uint32_t emittedChecksum(const char *buf)
46+
{
47+
const char *star = strrchr(buf, '*');
48+
TEST_ASSERT_NOT_NULL(star);
49+
unsigned parsed = 0;
50+
TEST_ASSERT_EQUAL_INT(1, sscanf(star + 1, "%02X", &parsed));
51+
return parsed;
52+
}
53+
54+
static void assertChecksumMatchesBody(const char *buf)
55+
{
56+
TEST_ASSERT_EQUAL_UINT32(expectedChecksum(buf), emittedChecksum(buf));
57+
}
58+
59+
void test_wpl_lite_checksum_skips_leading_crlf(void)
60+
{
61+
char buf[128];
62+
meshtastic_PositionLite pos = makePositionLite();
63+
uint32_t len = printWPL(buf, sizeof(buf), pos, "Test", false);
64+
65+
TEST_ASSERT_TRUE(len < sizeof(buf));
66+
TEST_ASSERT_EQUAL_CHAR('\r', buf[0]);
67+
TEST_ASSERT_EQUAL_CHAR('\n', buf[1]);
68+
TEST_ASSERT_EQUAL_CHAR('$', buf[2]);
69+
assertChecksumMatchesBody(buf);
70+
}
71+
72+
void test_wpl_position_checksum(void)
73+
{
74+
char buf[128];
75+
meshtastic_Position pos = makePosition();
76+
uint32_t len = printWPL(buf, sizeof(buf), pos, "Test", false);
77+
78+
TEST_ASSERT_TRUE(len < sizeof(buf));
79+
TEST_ASSERT_EQUAL_CHAR('$', buf[0]);
80+
assertChecksumMatchesBody(buf);
81+
}
82+
83+
void test_gga_checksum(void)
84+
{
85+
char buf[160];
86+
meshtastic_Position pos = makePosition();
87+
uint32_t len = printGGA(buf, sizeof(buf), pos);
88+
89+
TEST_ASSERT_TRUE(len < sizeof(buf));
90+
TEST_ASSERT_EQUAL_CHAR('$', buf[0]);
91+
assertChecksumMatchesBody(buf);
92+
}
93+
94+
void test_crlf_prefix_does_not_change_checksum(void)
95+
{
96+
char withPrefix[128];
97+
char withoutPrefix[128];
98+
meshtastic_PositionLite lite = makePositionLite();
99+
meshtastic_Position pos = makePosition();
100+
101+
printWPL(withPrefix, sizeof(withPrefix), lite, "Test", false);
102+
printWPL(withoutPrefix, sizeof(withoutPrefix), pos, "Test", false);
103+
104+
TEST_ASSERT_EQUAL_UINT32(emittedChecksum(withoutPrefix), emittedChecksum(withPrefix));
105+
}
106+
107+
void test_zero_sized_buffer_writes_nothing(void)
108+
{
109+
char buf[64];
110+
memset(buf, 'A', sizeof(buf));
111+
meshtastic_PositionLite lite = makePositionLite();
112+
meshtastic_Position pos = makePosition();
113+
114+
TEST_ASSERT_EQUAL_UINT32(0, printWPL(buf, 0, lite, "Test", false));
115+
TEST_ASSERT_EQUAL_UINT32(0, printWPL(buf, 0, pos, "Test", false));
116+
TEST_ASSERT_EQUAL_UINT32(0, printGGA(buf, 0, pos));
117+
118+
for (size_t i = 0; i < sizeof(buf); i++)
119+
TEST_ASSERT_EQUAL_CHAR('A', buf[i]);
120+
}
121+
122+
void test_truncated_buffers_stay_in_bounds(void)
123+
{
124+
const size_t sizes[] = {1, 2, 8, 20, 40};
125+
meshtastic_PositionLite lite = makePositionLite();
126+
127+
for (size_t s = 0; s < sizeof(sizes) / sizeof(sizes[0]); s++) {
128+
char buf[128];
129+
memset(buf, 0x7E, sizeof(buf));
130+
uint32_t len = printWPL(buf, sizes[s], lite, "Test", false);
131+
132+
TEST_ASSERT_TRUE(len < sizes[s]);
133+
for (size_t i = sizes[s]; i < sizeof(buf); i++)
134+
TEST_ASSERT_EQUAL_HEX8(0x7E, (uint8_t)buf[i]);
135+
}
136+
}
137+
138+
void setup()
139+
{
140+
initializeTestEnvironment();
141+
UNITY_BEGIN();
142+
RUN_TEST(test_wpl_lite_checksum_skips_leading_crlf);
143+
RUN_TEST(test_wpl_position_checksum);
144+
RUN_TEST(test_gga_checksum);
145+
RUN_TEST(test_crlf_prefix_does_not_change_checksum);
146+
RUN_TEST(test_zero_sized_buffer_writes_nothing);
147+
RUN_TEST(test_truncated_buffers_stay_in_bounds);
148+
exit(UNITY_END());
149+
}
150+
151+
void loop() {}

0 commit comments

Comments
 (0)