test: add lora frame and chunk reassembly logic suite

This commit is contained in:
2026-02-20 21:26:51 +01:00
parent cef1d184ed
commit ca2cd1880a
7 changed files with 380 additions and 91 deletions

View File

@@ -0,0 +1,131 @@
#include <Arduino.h>
#include <unity.h>
#include "batch_reassembly_logic.h"
#include "lora_frame_logic.h"
static void test_crc16_known_vectors() {
const uint8_t canonical[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
TEST_ASSERT_EQUAL_HEX16(0x29B1, lora_crc16_ccitt(canonical, sizeof(canonical)));
const uint8_t binary[] = {0x00, 0x01, 0x02, 0x03, 0x04};
TEST_ASSERT_EQUAL_HEX16(0x1C0F, lora_crc16_ccitt(binary, sizeof(binary)));
}
static void test_frame_encode_decode_and_crc_reject() {
const uint8_t payload[] = {0x01, 0x02, 0xA5};
uint8_t frame[64] = {};
size_t frame_len = 0;
TEST_ASSERT_TRUE(lora_build_frame(0, 0xF19C, payload, sizeof(payload), frame, sizeof(frame), frame_len));
TEST_ASSERT_EQUAL_UINT(8, frame_len);
uint8_t out_kind = 0xFF;
uint16_t out_device_id = 0;
uint8_t out_payload[16] = {};
size_t out_payload_len = 0;
LoraFrameDecodeStatus ok = lora_parse_frame(frame, frame_len, 1, &out_kind, &out_device_id, out_payload,
sizeof(out_payload), &out_payload_len);
TEST_ASSERT_EQUAL_UINT8(static_cast<uint8_t>(LoraFrameDecodeStatus::Ok), static_cast<uint8_t>(ok));
TEST_ASSERT_EQUAL_UINT8(0, out_kind);
TEST_ASSERT_EQUAL_UINT16(0xF19C, out_device_id);
TEST_ASSERT_EQUAL_UINT(sizeof(payload), out_payload_len);
TEST_ASSERT_EQUAL_UINT8_ARRAY(payload, out_payload, sizeof(payload));
frame[frame_len - 1] ^= 0x01;
LoraFrameDecodeStatus bad_crc = lora_parse_frame(frame, frame_len, 1, &out_kind, &out_device_id, out_payload,
sizeof(out_payload), &out_payload_len);
TEST_ASSERT_EQUAL_UINT8(static_cast<uint8_t>(LoraFrameDecodeStatus::CrcFail), static_cast<uint8_t>(bad_crc));
}
static void test_frame_rejects_invalid_msg_kind_and_short_length() {
const uint8_t payload[] = {0x42};
uint8_t frame[32] = {};
size_t frame_len = 0;
TEST_ASSERT_TRUE(lora_build_frame(2, 0xF19C, payload, sizeof(payload), frame, sizeof(frame), frame_len));
uint8_t out_kind = 0;
uint16_t out_device_id = 0;
uint8_t out_payload[8] = {};
size_t out_payload_len = 0;
LoraFrameDecodeStatus invalid_msg = lora_parse_frame(frame, frame_len, 1, &out_kind, &out_device_id, out_payload,
sizeof(out_payload), &out_payload_len);
TEST_ASSERT_EQUAL_UINT8(static_cast<uint8_t>(LoraFrameDecodeStatus::InvalidMsgKind), static_cast<uint8_t>(invalid_msg));
LoraFrameDecodeStatus short_len = lora_parse_frame(frame, 4, 1, &out_kind, &out_device_id, out_payload,
sizeof(out_payload), &out_payload_len);
TEST_ASSERT_EQUAL_UINT8(static_cast<uint8_t>(LoraFrameDecodeStatus::LengthMismatch), static_cast<uint8_t>(short_len));
}
static void test_chunk_reassembly_in_order_success() {
BatchReassemblyState state = {};
batch_reassembly_reset(state);
const uint8_t payload[] = {1, 2, 3, 4, 5, 6, 7};
uint8_t buffer[32] = {};
uint16_t complete_len = 0;
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::InProgress),
static_cast<uint8_t>(batch_reassembly_push(state, 77, 0, 3, 7, &payload[0], 3, 1000, 5000, 32, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::InProgress),
static_cast<uint8_t>(batch_reassembly_push(state, 77, 1, 3, 7, &payload[3], 2, 1100, 5000, 32, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::Complete),
static_cast<uint8_t>(batch_reassembly_push(state, 77, 2, 3, 7, &payload[5], 2, 1200, 5000, 32, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_EQUAL_UINT16(7, complete_len);
TEST_ASSERT_FALSE(state.active);
TEST_ASSERT_EQUAL_UINT8_ARRAY(payload, buffer, sizeof(payload));
}
static void test_chunk_reassembly_missing_or_out_of_order_fails_deterministically() {
BatchReassemblyState state = {};
batch_reassembly_reset(state);
const uint8_t payload[] = {9, 8, 7, 6, 5, 4};
uint8_t buffer[32] = {};
uint16_t complete_len = 0;
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::InProgress),
static_cast<uint8_t>(batch_reassembly_push(state, 10, 0, 3, 6, &payload[0], 2, 1000, 5000, 32, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::ErrorReset),
static_cast<uint8_t>(batch_reassembly_push(state, 10, 2, 3, 6, &payload[4], 2, 1100, 5000, 32, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_FALSE(state.active);
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::ErrorReset),
static_cast<uint8_t>(batch_reassembly_push(state, 11, 1, 3, 6, &payload[2], 2, 1200, 5000, 32, buffer, sizeof(buffer), complete_len)));
}
static void test_chunk_reassembly_wrong_total_length_fails() {
BatchReassemblyState state = {};
batch_reassembly_reset(state);
const uint8_t payload[] = {1, 2, 3, 4, 5, 6};
uint8_t buffer[8] = {};
uint16_t complete_len = 0;
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::InProgress),
static_cast<uint8_t>(batch_reassembly_push(state, 55, 0, 2, 5, &payload[0], 3, 1000, 5000, 8, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_EQUAL_UINT8(
static_cast<uint8_t>(BatchReassemblyStatus::ErrorReset),
static_cast<uint8_t>(batch_reassembly_push(state, 55, 1, 2, 5, &payload[3], 3, 1100, 5000, 8, buffer, sizeof(buffer), complete_len)));
TEST_ASSERT_FALSE(state.active);
}
void setup() {
UNITY_BEGIN();
RUN_TEST(test_crc16_known_vectors);
RUN_TEST(test_frame_encode_decode_and_crc_reject);
RUN_TEST(test_frame_rejects_invalid_msg_kind_and_short_length);
RUN_TEST(test_chunk_reassembly_in_order_success);
RUN_TEST(test_chunk_reassembly_missing_or_out_of_order_fails_deterministically);
RUN_TEST(test_chunk_reassembly_wrong_total_length_fails);
UNITY_END();
}
void loop() {}