STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_main.cpp
Go to the documentation of this file.
1// Host tests for frame.cpp. Run on a laptop: no hardware.
2#include <string.h>
3
4#include "unity.h"
5
6// Build the code under test.
8
9using namespace radio_link;
10
11void setUp(void) {
12}
13void tearDown(void) {
14}
15
16// Golden frames computed by an independent Python implementation of the layout
17// in frame.h, so these catch a mistake shared by encode and decode.
18static const uint8_t GOLDEN_UN_ARM[] = {0x01, 0x11, 0x02, 0x01,
19 0x00, 0x1F, 0x8B};
20static const uint8_t GOLDEN_ARM[] = {0x01, 0x10, 0x01, 0x00, 0x09, 0x5A,
21 0x96, 0xC3, 0xA5, 0xA5, 0x69, 0x3C,
22 0x5A, 0x07, 0xFA, 0xCF};
23static const uint8_t GOLDEN_HEARTBEAT[] = {0x01, 0x01, 0xEF, 0xBE, 0x07,
24 0x03, 0xE8, 0x1C, 0x40, 0xE2,
25 0x01, 0x00, 0xFD, 0x1B};
26
27// Build a frame by hand (bypassing encode_frame's checks) with a valid CRC.
28static size_t raw_frame(uint8_t* out, uint8_t type, uint16_t seq,
29 const uint8_t* payload, uint8_t plen) {
30 out[0] = kFrameVersion;
31 out[1] = type;
32 put_u16(out + 2, seq);
33 out[4] = plen;
34 if (plen) {
35 memcpy(out + 5, payload, plen);
36 }
37 put_u16(out + 5 + plen, crc16(out, 5u + plen));
38 return 7u + plen;
39}
40
42 TEST_ASSERT_EQUAL_HEX16(
43 0x29B1, crc16(reinterpret_cast<const uint8_t*>("123456789"), 9));
44}
45
47 TEST_ASSERT_EQUAL_HEX16(0xFFFF,
48 crc16(reinterpret_cast<const uint8_t*>(""), 0));
49}
50
51static void test_little_endian_helpers(void) {
52 uint8_t b[4];
53 put_u32(b, 0x01020304u);
54 TEST_ASSERT_EQUAL_HEX8(0x04, b[0]);
55 TEST_ASSERT_EQUAL_HEX8(0x01, b[3]);
56 TEST_ASSERT_EQUAL_HEX32(0x01020304u, get_u32(b));
57 put_u16(b, 0xBEEF);
58 TEST_ASSERT_EQUAL_HEX8(0xEF, b[0]);
59 TEST_ASSERT_EQUAL_HEX16(0xBEEF, get_u16(b));
60}
61
63 uint8_t out[kFrameMaxLen];
64 size_t n = 0;
65 TEST_ASSERT_EQUAL(
67 encode_frame(FrameType::UnArm, 0x0102, nullptr, 0, out, sizeof out, n));
68 TEST_ASSERT_EQUAL_UINT(sizeof GOLDEN_UN_ARM, n);
69 TEST_ASSERT_EQUAL_HEX8_ARRAY(GOLDEN_UN_ARM, out, n);
70}
71
73 uint8_t payload[9];
74 put_u32(payload, 0xA5C3965Au);
75 put_u32(payload + 4, ~0xA5C3965Au);
76 payload[8] = 7;
77 uint8_t out[kFrameMaxLen];
78 size_t n = 0;
80 9, out, sizeof out, n));
81 TEST_ASSERT_EQUAL_UINT(sizeof GOLDEN_ARM, n);
82 TEST_ASSERT_EQUAL_HEX8_ARRAY(GOLDEN_ARM, out, n);
83}
84
86 Frame f;
87 TEST_ASSERT_EQUAL(
90 TEST_ASSERT_EQUAL(FrameType::Heartbeat, f.type);
91 TEST_ASSERT_EQUAL_HEX16(0xBEEF, f.seq);
92 TEST_ASSERT_EQUAL_UINT8(7, f.payload_len);
93 TEST_ASSERT_EQUAL_UINT8(3, f.payload[0]); // state
94 TEST_ASSERT_EQUAL_UINT16(7400, get_u16(f.payload + 1)); // battery mV
95 TEST_ASSERT_EQUAL_UINT32(123456, get_u32(f.payload + 3)); // uptime s
96}
97
98static void test_roundtrip_every_type(void) {
99 static const struct {
100 FrameType type;
101 uint8_t len;
102 } cases[] = {{FrameType::Heartbeat, 7},
104 {FrameType::Arm, 9},
105 {FrameType::UnArm, 0}};
106 for (unsigned i = 0; i < sizeof cases / sizeof cases[0]; i++) {
107 uint8_t payload[9];
108 for (unsigned k = 0; k < sizeof payload; k++) {
109 payload[k] = static_cast<uint8_t>(0x30 + k);
110 }
111 uint8_t out[kFrameMaxLen];
112 size_t n = 0;
113 Frame f;
114 TEST_ASSERT_EQUAL(FrameStatus::Ok,
115 encode_frame(cases[i].type, 0xFFFF, payload,
116 cases[i].len, out, sizeof out, n));
117 TEST_ASSERT_EQUAL_UINT(7u + cases[i].len, n);
118 TEST_ASSERT_EQUAL(FrameStatus::Ok, decode_frame(out, n, f));
119 TEST_ASSERT_EQUAL(cases[i].type, f.type);
120 TEST_ASSERT_EQUAL_HEX16(0xFFFF, f.seq);
121 TEST_ASSERT_EQUAL_UINT8(cases[i].len, f.payload_len);
122 if (cases[i].len > 0) { // Unity rejects zero-length array compares
123 TEST_ASSERT_EQUAL_HEX8_ARRAY(payload, f.payload, cases[i].len);
124 }
125 }
126}
127
129 Frame f;
130 TEST_ASSERT_EQUAL(FrameStatus::ErrTooShort,
132 TEST_ASSERT_EQUAL(FrameStatus::ErrTooShort,
134}
135
137 Frame f;
138 TEST_ASSERT_EQUAL(FrameStatus::ErrArgs, decode_frame(nullptr, 7, f));
139}
140
142 uint8_t b[16];
143 const size_t n =
144 raw_frame(b, static_cast<uint8_t>(FrameType::UnArm), 1, nullptr, 0);
145 b[0] = 0x02; // CRC now wrong too, but version is checked first
146 Frame f;
147 TEST_ASSERT_EQUAL(FrameStatus::ErrVersion, decode_frame(b, n, f));
148}
149
151 uint8_t b[32];
152 const size_t n =
153 raw_frame(b, static_cast<uint8_t>(FrameType::UnArm), 1, nullptr, 0);
154 Frame f;
155 b[n] = 0x00; // one trailing byte
156 TEST_ASSERT_EQUAL(FrameStatus::ErrLength, decode_frame(b, n + 1, f));
157 TEST_ASSERT_EQUAL(FrameStatus::ErrTooShort, decode_frame(b, n - 1, f));
158 // Truncated ARM: length field says 9 but bytes are missing.
159 TEST_ASSERT_EQUAL(FrameStatus::ErrLength,
160 decode_frame(GOLDEN_ARM, sizeof GOLDEN_ARM - 1, f));
161}
162
164 uint8_t b[300];
165 memset(b, 0, sizeof b);
166 b[0] = kFrameVersion;
167 b[1] = static_cast<uint8_t>(FrameType::Heartbeat);
168 b[4] = 249; // > kFrameMaxPayload
169 Frame f;
170 TEST_ASSERT_EQUAL(FrameStatus::ErrLength, decode_frame(b, 7u + 249u, f));
171}
172
174 // CRC-16 detects every single-bit error: flip each bit of each byte of a
175 // valid ARM frame and confirm none of them decodes as Ok.
176 uint8_t b[sizeof GOLDEN_ARM];
177 Frame f;
178 for (unsigned i = 0; i < sizeof b; i++) {
179 for (unsigned bit = 0; bit < 8; bit++) {
180 memcpy(b, GOLDEN_ARM, sizeof b);
181 b[i] ^= static_cast<uint8_t>(1u << bit);
182 TEST_ASSERT_NOT_EQUAL_MESSAGE(
183 static_cast<int>(FrameStatus::Ok),
184 static_cast<int>(decode_frame(b, sizeof b, f)),
185 "corrupted frame was accepted");
186 }
187 }
188}
189
191 uint8_t b[16];
192 const size_t n = raw_frame(b, 0x7F, 1, nullptr, 0);
193 Frame f;
194 TEST_ASSERT_EQUAL(FrameStatus::ErrType, decode_frame(b, n, f));
195}
196
198 uint8_t payload[8] = {0};
199 uint8_t b[32];
200 Frame f;
201 // ARM must be exactly 9 bytes.
202 size_t n =
203 raw_frame(b, static_cast<uint8_t>(FrameType::Arm), 1, payload, 8);
204 TEST_ASSERT_EQUAL(FrameStatus::ErrPayload, decode_frame(b, n, f));
205 // UN_ARM must be empty.
206 n = raw_frame(b, static_cast<uint8_t>(FrameType::UnArm), 1, payload, 1);
207 TEST_ASSERT_EQUAL(FrameStatus::ErrPayload, decode_frame(b, n, f));
208}
209
211 uint8_t payload[9] = {0};
212 uint8_t out[kFrameMaxLen];
213 size_t n = 0;
214 TEST_ASSERT_EQUAL(FrameStatus::ErrType,
215 encode_frame(static_cast<FrameType>(0x7F), 0, nullptr, 0,
216 out, sizeof out, n));
217 TEST_ASSERT_EQUAL(
219 encode_frame(FrameType::Arm, 0, payload, 8, out, sizeof out, n));
220 TEST_ASSERT_EQUAL(FrameStatus::ErrArgs,
221 encode_frame(FrameType::Arm, 0, payload, 9, out, 15, n));
222 TEST_ASSERT_EQUAL(
224 encode_frame(FrameType::Arm, 0, nullptr, 9, out, sizeof out, n));
225}
226
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
Definition json.hpp:13878
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
int main()
static void test_roundtrip_every_type(void)
Definition test_main.cpp:98
static void test_decode_rejects_too_short(void)
static void test_decode_rejects_null_buffer(void)
static void test_encode_matches_golden_un_arm(void)
Definition test_main.cpp:62
static const uint8_t GOLDEN_UN_ARM[]
Definition test_main.cpp:18
static size_t raw_frame(uint8_t *out, uint8_t type, uint16_t seq, const uint8_t *payload, uint8_t plen)
Definition test_main.cpp:28
static void test_decode_rejects_oversize_length_field(void)
static void test_decode_rejects_extra_or_missing_bytes(void)
static void test_decode_rejects_any_single_bit_flip(void)
static void test_encode_matches_golden_arm(void)
Definition test_main.cpp:72
static void test_decode_rejects_wrong_payload_size_with_valid_crc(void)
static void test_little_endian_helpers(void)
Definition test_main.cpp:51
void setUp(void)
Definition test_main.cpp:11
void tearDown(void)
Definition test_main.cpp:13
static void test_decode_rejects_wrong_version(void)
static const uint8_t GOLDEN_HEARTBEAT[]
Definition test_main.cpp:23
static void test_decode_golden_heartbeat(void)
Definition test_main.cpp:85
static const uint8_t GOLDEN_ARM[]
Definition test_main.cpp:20
static void test_decode_rejects_unknown_type_with_valid_crc(void)
static void test_crc16_standard_check_value(void)
Definition test_main.cpp:41
static void test_encode_rejects_bad_inputs(void)
static void test_crc16_empty_is_init_value(void)
Definition test_main.cpp:46