bring back tests

This commit is contained in:
Thomas Göttgens
2026-04-14 09:06:56 +02:00
parent 0f7a6d8b3b
commit 4e000ee4ce
8 changed files with 694 additions and 0 deletions
@@ -0,0 +1,47 @@
#include "../test_helpers.h"
static void assert_encrypted_packet(const std::string &json, const meshtastic_MeshPacket &packet)
{
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("from"));
TEST_ASSERT_EQUAL(packet.from, root["from"].asUInt());
TEST_ASSERT_TRUE(root.isMember("to"));
TEST_ASSERT_EQUAL(packet.to, root["to"].asUInt());
TEST_ASSERT_TRUE(root.isMember("id"));
TEST_ASSERT_EQUAL(packet.id, root["id"].asUInt());
TEST_ASSERT_TRUE(root.isMember("bytes"));
TEST_ASSERT_TRUE(root["bytes"].isString());
TEST_ASSERT_TRUE(root.isMember("size"));
TEST_ASSERT_EQUAL(packet.encrypted.size, (int)root["size"].asInt());
std::string encrypted_hex = root["bytes"].asString();
TEST_ASSERT_EQUAL(packet.encrypted.size * 2, encrypted_hex.length());
}
void test_encrypted_packet_serialization()
{
const char *data = "encrypted_payload_data";
meshtastic_MeshPacket packet =
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, reinterpret_cast<const uint8_t *>(data), strlen(data),
meshtastic_MeshPacket_encrypted_tag);
std::string json = MeshPacketSerializer::JsonSerializeEncrypted(&packet);
assert_encrypted_packet(json, packet);
}
void test_empty_encrypted_packet()
{
meshtastic_MeshPacket packet =
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, nullptr, 0, meshtastic_MeshPacket_encrypted_tag);
std::string json = MeshPacketSerializer::JsonSerializeEncrypted(&packet);
assert_encrypted_packet(json, packet);
}
@@ -0,0 +1,42 @@
#include "../test_helpers.h"
static size_t encode_user_info(uint8_t *buffer, size_t buffer_size)
{
meshtastic_User user = meshtastic_User_init_zero;
strcpy(user.short_name, "TEST");
strcpy(user.long_name, "Test User");
strcpy(user.id, "!12345678");
user.hw_model = meshtastic_HardwareModel_HELTEC_V3;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_User_msg, &user);
return stream.bytes_written;
}
void test_nodeinfo_serialization()
{
uint8_t buffer[256];
size_t payload_size = encode_user_info(buffer, sizeof(buffer));
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_NODEINFO_APP, buffer, payload_size);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("type"));
TEST_ASSERT_EQUAL_STRING("nodeinfo", root["type"].asString().c_str());
TEST_ASSERT_TRUE(root.isMember("payload"));
TEST_ASSERT_TRUE(root["payload"].isObject());
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("shortname"));
TEST_ASSERT_EQUAL_STRING("TEST", payload["shortname"].asString().c_str());
TEST_ASSERT_TRUE(payload.isMember("longname"));
TEST_ASSERT_EQUAL_STRING("Test User", payload["longname"].asString().c_str());
}
@@ -0,0 +1,48 @@
#include "../test_helpers.h"
static size_t encode_position(uint8_t *buffer, size_t buffer_size)
{
meshtastic_Position position = meshtastic_Position_init_zero;
position.latitude_i = 374208000;
position.longitude_i = -1221981000;
position.altitude = 123;
position.time = 1609459200;
position.has_altitude = true;
position.has_latitude_i = true;
position.has_longitude_i = true;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_Position_msg, &position);
return stream.bytes_written;
}
void test_position_serialization()
{
uint8_t buffer[256];
size_t payload_size = encode_position(buffer, sizeof(buffer));
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_POSITION_APP, buffer, payload_size);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("type"));
TEST_ASSERT_EQUAL_STRING("position", root["type"].asString().c_str());
TEST_ASSERT_TRUE(root.isMember("payload"));
TEST_ASSERT_TRUE(root["payload"].isObject());
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("latitude_i"));
TEST_ASSERT_EQUAL(374208000, payload["latitude_i"].asInt());
TEST_ASSERT_TRUE(payload.isMember("longitude_i"));
TEST_ASSERT_EQUAL(-1221981000, payload["longitude_i"].asInt());
TEST_ASSERT_TRUE(payload.isMember("altitude"));
TEST_ASSERT_EQUAL(123, payload["altitude"].asInt());
}
@@ -0,0 +1,310 @@
#include "../test_helpers.h"
static void fill_all_env_metrics(meshtastic_Telemetry &telemetry)
{
telemetry.variant.environment_metrics.temperature = 23.56f;
telemetry.variant.environment_metrics.has_temperature = true;
telemetry.variant.environment_metrics.relative_humidity = 65.43f;
telemetry.variant.environment_metrics.has_relative_humidity = true;
telemetry.variant.environment_metrics.barometric_pressure = 1013.27f;
telemetry.variant.environment_metrics.has_barometric_pressure = true;
telemetry.variant.environment_metrics.gas_resistance = 50.58f;
telemetry.variant.environment_metrics.has_gas_resistance = true;
telemetry.variant.environment_metrics.iaq = 120;
telemetry.variant.environment_metrics.has_iaq = true;
telemetry.variant.environment_metrics.voltage = 3.34f;
telemetry.variant.environment_metrics.has_voltage = true;
telemetry.variant.environment_metrics.current = 0.53f;
telemetry.variant.environment_metrics.has_current = true;
telemetry.variant.environment_metrics.lux = 450.12f;
telemetry.variant.environment_metrics.has_lux = true;
telemetry.variant.environment_metrics.white_lux = 380.95f;
telemetry.variant.environment_metrics.has_white_lux = true;
telemetry.variant.environment_metrics.ir_lux = 25.37f;
telemetry.variant.environment_metrics.has_ir_lux = true;
telemetry.variant.environment_metrics.uv_lux = 15.68f;
telemetry.variant.environment_metrics.has_uv_lux = true;
telemetry.variant.environment_metrics.distance = 150.29f;
telemetry.variant.environment_metrics.has_distance = true;
telemetry.variant.environment_metrics.wind_direction = 180;
telemetry.variant.environment_metrics.has_wind_direction = true;
telemetry.variant.environment_metrics.wind_speed = 5.52f;
telemetry.variant.environment_metrics.has_wind_speed = true;
telemetry.variant.environment_metrics.wind_gust = 8.24f;
telemetry.variant.environment_metrics.has_wind_gust = true;
telemetry.variant.environment_metrics.wind_lull = 2.13f;
telemetry.variant.environment_metrics.has_wind_lull = true;
telemetry.variant.environment_metrics.weight = 75.56f;
telemetry.variant.environment_metrics.has_weight = true;
telemetry.variant.environment_metrics.radiation = 0.13f;
telemetry.variant.environment_metrics.has_radiation = true;
telemetry.variant.environment_metrics.rainfall_1h = 2.57f;
telemetry.variant.environment_metrics.has_rainfall_1h = true;
telemetry.variant.environment_metrics.rainfall_24h = 15.89f;
telemetry.variant.environment_metrics.has_rainfall_24h = true;
telemetry.variant.environment_metrics.soil_moisture = 85;
telemetry.variant.environment_metrics.has_soil_moisture = true;
telemetry.variant.environment_metrics.soil_temperature = 18.54f;
telemetry.variant.environment_metrics.has_soil_temperature = true;
}
static size_t encode_telemetry_device_metrics(uint8_t *buffer, size_t buffer_size)
{
meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero;
telemetry.time = 1609459200;
telemetry.which_variant = meshtastic_Telemetry_device_metrics_tag;
telemetry.variant.device_metrics.battery_level = 85;
telemetry.variant.device_metrics.has_battery_level = true;
telemetry.variant.device_metrics.voltage = 3.72f;
telemetry.variant.device_metrics.has_voltage = true;
telemetry.variant.device_metrics.channel_utilization = 15.56f;
telemetry.variant.device_metrics.has_channel_utilization = true;
telemetry.variant.device_metrics.air_util_tx = 8.23f;
telemetry.variant.device_metrics.has_air_util_tx = true;
telemetry.variant.device_metrics.uptime_seconds = 12345;
telemetry.variant.device_metrics.has_uptime_seconds = true;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_Telemetry_msg, &telemetry);
return stream.bytes_written;
}
static size_t encode_telemetry_environment_metrics_empty(uint8_t *buffer, size_t buffer_size)
{
meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero;
telemetry.time = 1609459200;
telemetry.which_variant = meshtastic_Telemetry_environment_metrics_tag;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_Telemetry_msg, &telemetry);
return stream.bytes_written;
}
static size_t encode_telemetry_environment_metrics(uint8_t *buffer, size_t buffer_size)
{
meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero;
telemetry.time = 1609459200;
telemetry.which_variant = meshtastic_Telemetry_environment_metrics_tag;
fill_all_env_metrics(telemetry);
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_Telemetry_msg, &telemetry);
return stream.bytes_written;
}
static Json::Value serialize_and_get_payload(meshtastic_PortNum port, const uint8_t *buffer, size_t payload_size)
{
meshtastic_MeshPacket packet = create_test_packet(port, buffer, payload_size);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("payload"));
TEST_ASSERT_TRUE(root["payload"].isObject());
return root;
}
void test_telemetry_device_metrics_serialization()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_device_metrics(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
TEST_ASSERT_TRUE(root.isMember("type"));
TEST_ASSERT_EQUAL_STRING("telemetry", root["type"].asString().c_str());
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("battery_level"));
TEST_ASSERT_EQUAL(85, payload["battery_level"].asInt());
TEST_ASSERT_TRUE(payload.isMember("voltage"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 3.72f, payload["voltage"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("channel_utilization"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 15.56f, payload["channel_utilization"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("uptime_seconds"));
TEST_ASSERT_EQUAL(12345, payload["uptime_seconds"].asInt());
}
void test_telemetry_environment_metrics_serialization()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_environment_metrics(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("temperature"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 23.56f, payload["temperature"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("relative_humidity"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 65.43f, payload["relative_humidity"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("distance"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 150.29f, payload["distance"].asFloat());
}
void test_telemetry_environment_metrics_comprehensive()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_environment_metrics(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("temperature"));
TEST_ASSERT_TRUE(payload.isMember("relative_humidity"));
TEST_ASSERT_TRUE(payload.isMember("barometric_pressure"));
TEST_ASSERT_TRUE(payload.isMember("gas_resistance"));
TEST_ASSERT_TRUE(payload.isMember("voltage"));
TEST_ASSERT_TRUE(payload.isMember("current"));
TEST_ASSERT_TRUE(payload.isMember("iaq"));
TEST_ASSERT_TRUE(payload.isMember("distance"));
TEST_ASSERT_TRUE(payload.isMember("lux"));
TEST_ASSERT_TRUE(payload.isMember("white_lux"));
TEST_ASSERT_TRUE(payload.isMember("wind_direction"));
TEST_ASSERT_TRUE(payload.isMember("wind_speed"));
TEST_ASSERT_TRUE(payload.isMember("wind_gust"));
TEST_ASSERT_TRUE(payload.isMember("wind_lull"));
TEST_ASSERT_TRUE(payload.isMember("radiation"));
}
void test_telemetry_environment_metrics_missing_fields()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_environment_metrics(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("ir_lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 25.37f, payload["ir_lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("uv_lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 15.68f, payload["uv_lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("weight"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 75.56f, payload["weight"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("rainfall_1h"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 2.57f, payload["rainfall_1h"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("rainfall_24h"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 15.89f, payload["rainfall_24h"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("soil_moisture"));
TEST_ASSERT_EQUAL(85, payload["soil_moisture"].asInt());
TEST_ASSERT_TRUE(payload.isMember("soil_temperature"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 18.54f, payload["soil_temperature"].asFloat());
}
// Canary test: if a new env field is added to the protobuf but not to the serializer
// (or to fill_all_env_metrics), this test will fail.
void test_telemetry_environment_metrics_complete_coverage()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_environment_metrics(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("temperature"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 23.56f, payload["temperature"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("relative_humidity"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 65.43f, payload["relative_humidity"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("barometric_pressure"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 1013.27f, payload["barometric_pressure"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("gas_resistance"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 50.58f, payload["gas_resistance"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("iaq"));
TEST_ASSERT_EQUAL(120, payload["iaq"].asInt());
TEST_ASSERT_TRUE(payload.isMember("voltage"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 3.34f, payload["voltage"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("current"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 0.53f, payload["current"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 450.12f, payload["lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("white_lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 380.95f, payload["white_lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("ir_lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 25.37f, payload["ir_lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("uv_lux"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 15.68f, payload["uv_lux"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("distance"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 150.29f, payload["distance"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("wind_direction"));
TEST_ASSERT_EQUAL(180, payload["wind_direction"].asInt());
TEST_ASSERT_TRUE(payload.isMember("wind_speed"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 5.52f, payload["wind_speed"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("wind_gust"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 8.24f, payload["wind_gust"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("wind_lull"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 2.13f, payload["wind_lull"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("weight"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 75.56f, payload["weight"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("radiation"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 0.13f, payload["radiation"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("rainfall_1h"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 2.57f, payload["rainfall_1h"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("rainfall_24h"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 15.89f, payload["rainfall_24h"].asFloat());
TEST_ASSERT_TRUE(payload.isMember("soil_moisture"));
TEST_ASSERT_EQUAL(85, payload["soil_moisture"].asInt());
TEST_ASSERT_TRUE(payload.isMember("soil_temperature"));
TEST_ASSERT_FLOAT_WITHIN(0.01f, 18.54f, payload["soil_temperature"].asFloat());
}
void test_telemetry_environment_metrics_unset_fields()
{
uint8_t buffer[256];
size_t payload_size = encode_telemetry_environment_metrics_empty(buffer, sizeof(buffer));
Json::Value root = serialize_and_get_payload(meshtastic_PortNum_TELEMETRY_APP, buffer, payload_size);
const Json::Value &payload = root["payload"];
TEST_ASSERT_FALSE(payload.isMember("temperature"));
TEST_ASSERT_FALSE(payload.isMember("relative_humidity"));
TEST_ASSERT_FALSE(payload.isMember("barometric_pressure"));
TEST_ASSERT_FALSE(payload.isMember("gas_resistance"));
TEST_ASSERT_FALSE(payload.isMember("iaq"));
TEST_ASSERT_FALSE(payload.isMember("voltage"));
TEST_ASSERT_FALSE(payload.isMember("current"));
TEST_ASSERT_FALSE(payload.isMember("lux"));
TEST_ASSERT_FALSE(payload.isMember("white_lux"));
TEST_ASSERT_FALSE(payload.isMember("ir_lux"));
TEST_ASSERT_FALSE(payload.isMember("uv_lux"));
TEST_ASSERT_FALSE(payload.isMember("distance"));
TEST_ASSERT_FALSE(payload.isMember("wind_direction"));
TEST_ASSERT_FALSE(payload.isMember("wind_speed"));
TEST_ASSERT_FALSE(payload.isMember("wind_gust"));
TEST_ASSERT_FALSE(payload.isMember("wind_lull"));
TEST_ASSERT_FALSE(payload.isMember("weight"));
TEST_ASSERT_FALSE(payload.isMember("radiation"));
TEST_ASSERT_FALSE(payload.isMember("rainfall_1h"));
TEST_ASSERT_FALSE(payload.isMember("rainfall_24h"));
TEST_ASSERT_FALSE(payload.isMember("soil_moisture"));
TEST_ASSERT_FALSE(payload.isMember("soil_temperature"));
}
@@ -0,0 +1,79 @@
#include "../test_helpers.h"
static void verify_text_message_packet_structure(const std::string &json, const char *expected_text)
{
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("from"));
TEST_ASSERT_EQUAL(0x11223344u, root["from"].asUInt());
TEST_ASSERT_TRUE(root.isMember("to"));
TEST_ASSERT_EQUAL(0x55667788u, root["to"].asUInt());
TEST_ASSERT_TRUE(root.isMember("id"));
TEST_ASSERT_EQUAL(0x9999u, root["id"].asUInt());
TEST_ASSERT_TRUE(root.isMember("type"));
TEST_ASSERT_EQUAL_STRING("text", root["type"].asString().c_str());
TEST_ASSERT_TRUE(root.isMember("payload"));
TEST_ASSERT_TRUE(root["payload"].isObject());
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("text"));
TEST_ASSERT_EQUAL_STRING(expected_text, payload["text"].asString().c_str());
}
void test_text_message_serialization()
{
const char *test_text = "Hello Meshtastic!";
meshtastic_MeshPacket packet =
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, reinterpret_cast<const uint8_t *>(test_text), strlen(test_text));
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
verify_text_message_packet_structure(json, test_text);
}
void test_text_message_serialization_null()
{
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, nullptr, 0);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
verify_text_message_packet_structure(json, "");
}
void test_text_message_serialization_long_text()
{
constexpr size_t MAX_MESSAGE_SIZE = 200;
std::string long_text(MAX_MESSAGE_SIZE, 'A');
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP,
reinterpret_cast<const uint8_t *>(long_text.c_str()), long_text.length());
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
verify_text_message_packet_structure(json, long_text.c_str());
}
void test_text_message_serialization_oversized()
{
constexpr size_t OVERSIZED_MESSAGE = 250;
std::string oversized_text(OVERSIZED_MESSAGE, 'B');
meshtastic_MeshPacket packet = create_test_packet(
meshtastic_PortNum_TEXT_MESSAGE_APP, reinterpret_cast<const uint8_t *>(oversized_text.c_str()), oversized_text.length());
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
std::string expected_text = oversized_text.substr(0, 234);
verify_text_message_packet_structure(json, expected_text.c_str());
}
void test_text_message_serialization_invalid_utf8()
{
const uint8_t invalid_utf8[] = {0xFF, 0xFE, 0xFD, 0x00};
meshtastic_MeshPacket packet =
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, invalid_utf8, sizeof(invalid_utf8) - 1);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
TEST_ASSERT_TRUE(json.length() > 0);
}
@@ -0,0 +1,44 @@
#include "../test_helpers.h"
static size_t encode_waypoint(uint8_t *buffer, size_t buffer_size)
{
meshtastic_Waypoint waypoint = meshtastic_Waypoint_init_zero;
waypoint.id = 12345;
waypoint.latitude_i = 374208000;
waypoint.longitude_i = -1221981000;
waypoint.expire = 1609459200 + 3600;
strcpy(waypoint.name, "Test Point");
strcpy(waypoint.description, "Test waypoint description");
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buffer_size);
pb_encode(&stream, &meshtastic_Waypoint_msg, &waypoint);
return stream.bytes_written;
}
void test_waypoint_serialization()
{
uint8_t buffer[256];
size_t payload_size = encode_waypoint(buffer, sizeof(buffer));
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_WAYPOINT_APP, buffer, payload_size);
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
TEST_ASSERT_TRUE(json.length() > 0);
Json::Value root = parse_json(json);
TEST_ASSERT_TRUE(root.isObject());
TEST_ASSERT_TRUE(root.isMember("type"));
TEST_ASSERT_EQUAL_STRING("waypoint", root["type"].asString().c_str());
TEST_ASSERT_TRUE(root.isMember("payload"));
TEST_ASSERT_TRUE(root["payload"].isObject());
const Json::Value &payload = root["payload"];
TEST_ASSERT_TRUE(payload.isMember("id"));
TEST_ASSERT_EQUAL(12345, payload["id"].asInt());
TEST_ASSERT_TRUE(payload.isMember("name"));
TEST_ASSERT_EQUAL_STRING("Test Point", payload["name"].asString().c_str());
}
@@ -0,0 +1,63 @@
#pragma once
#include "serialization/MeshPacketSerializer.h"
#include <Arduino.h>
#include <json/json.h>
#include <memory>
#include <meshtastic/mesh.pb.h>
#include <meshtastic/mqtt.pb.h>
#include <meshtastic/telemetry.pb.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include <unity.h>
// Parse a JSON string into a Json::Value; returns Json::nullValue on failure.
static inline Json::Value parse_json(const std::string &s)
{
Json::CharReaderBuilder b;
Json::Value root;
std::string errs;
std::unique_ptr<Json::CharReader> reader(b.newCharReader());
if (!reader->parse(s.c_str(), s.c_str() + s.size(), &root, &errs))
return Json::Value();
return root;
}
// Helper function to create a test packet with the given port and payload
static meshtastic_MeshPacket create_test_packet(meshtastic_PortNum port, const uint8_t *payload, size_t payload_size,
int payload_variant = meshtastic_MeshPacket_decoded_tag)
{
meshtastic_MeshPacket packet = meshtastic_MeshPacket_init_zero;
packet.id = 0x9999;
packet.from = 0x11223344;
packet.to = 0x55667788;
packet.channel = 0;
packet.hop_limit = 3;
packet.want_ack = false;
packet.priority = meshtastic_MeshPacket_Priority_UNSET;
packet.rx_time = 1609459200;
packet.rx_snr = 10.5f;
packet.hop_start = 3;
packet.rx_rssi = -85;
packet.delayed = meshtastic_MeshPacket_Delayed_NO_DELAY;
// Set decoded variant
packet.which_payload_variant = payload_variant;
packet.decoded.portnum = port;
if (payload_variant == meshtastic_MeshPacket_encrypted_tag && payload) {
packet.encrypted.size = payload_size;
memcpy(packet.encrypted.bytes, payload, packet.encrypted.size);
}
if (payload && payload_size)
memcpy(packet.decoded.payload.bytes, payload, payload_size);
packet.decoded.payload.size = payload_size;
packet.decoded.want_response = false;
packet.decoded.dest = 0x55667788;
packet.decoded.source = 0x11223344;
packet.decoded.request_id = 0;
packet.decoded.reply_id = 0;
packet.decoded.emoji = 0;
return packet;
}
@@ -0,0 +1,61 @@
#include "test_helpers.h"
#include <Arduino.h>
#include <unity.h>
// Forward declarations for test functions
void test_text_message_serialization();
void test_text_message_serialization_null();
void test_text_message_serialization_long_text();
void test_text_message_serialization_oversized();
void test_text_message_serialization_invalid_utf8();
void test_position_serialization();
void test_nodeinfo_serialization();
void test_waypoint_serialization();
void test_telemetry_device_metrics_serialization();
void test_telemetry_environment_metrics_serialization();
void test_telemetry_environment_metrics_comprehensive();
void test_telemetry_environment_metrics_missing_fields();
void test_telemetry_environment_metrics_complete_coverage();
void test_telemetry_environment_metrics_unset_fields();
void test_encrypted_packet_serialization();
void test_empty_encrypted_packet();
void setup()
{
UNITY_BEGIN();
// Text message tests
RUN_TEST(test_text_message_serialization);
RUN_TEST(test_text_message_serialization_null);
RUN_TEST(test_text_message_serialization_long_text);
RUN_TEST(test_text_message_serialization_oversized);
RUN_TEST(test_text_message_serialization_invalid_utf8);
// Position tests
RUN_TEST(test_position_serialization);
// Nodeinfo tests
RUN_TEST(test_nodeinfo_serialization);
// Waypoint tests
RUN_TEST(test_waypoint_serialization);
// Telemetry tests
RUN_TEST(test_telemetry_device_metrics_serialization);
RUN_TEST(test_telemetry_environment_metrics_serialization);
RUN_TEST(test_telemetry_environment_metrics_comprehensive);
RUN_TEST(test_telemetry_environment_metrics_missing_fields);
RUN_TEST(test_telemetry_environment_metrics_complete_coverage);
RUN_TEST(test_telemetry_environment_metrics_unset_fields);
// Encrypted packet test
RUN_TEST(test_encrypted_packet_serialization);
RUN_TEST(test_empty_encrypted_packet);
UNITY_END();
}
void loop()
{
delay(1000);
}