Fix long name clamping and adjust related structures for compatibility

This commit is contained in:
Ben Meadors
2026-06-11 12:18:26 -05:00
parent 8bb5364d8c
commit c2bcec93d0
12 changed files with 146 additions and 12 deletions
+47 -1
View File
@@ -1,6 +1,8 @@
// Tests for src/mesh/TypeConversions.cpp covering:
// - bitfield bit collapse on store + extraction round-trip
// - long_name / short_name truncation at the new max_size:25 / 5 boundaries
// - long_name / short_name truncation at the storage boundaries (wire User
// stays 40 wide for decoding legacy senders; NodeInfoLite stores 25 / 5)
// - wire-level decode acceptance of legacy 39-byte long_names
// - public_key / hw_model / role pass-through
// - thin vs bundled NodeInfo emission
//
@@ -10,6 +12,8 @@
#include "NodeDB.h"
#include "TestUtil.h"
#include "TypeConversions.h"
#include "mesh-pb-constants.h"
#include "meshUtils.h"
#include <cstdio>
#include <cstring>
#include <unity.h>
@@ -128,6 +132,46 @@ void test_long_name_truncated_utf8_boundary_sanitized(void)
TEST_ASSERT_EQUAL_INT('?', lite.long_name[23]);
}
// ---------- wire decode width (decode-liberal, store-narrow) ------------------
// Hand-built wire-format User payload: field 2 (long_name), wire type 2.
static size_t makeUserPayload(uint8_t *buf, size_t nameLen)
{
size_t i = 0;
buf[i++] = 0x12; // tag: field 2, length-delimited
buf[i++] = (uint8_t)nameLen;
for (size_t j = 0; j < nameLen; j++)
buf[i++] = (uint8_t)('A' + (j % 26));
return i;
}
void test_wire_decode_accepts_legacy_39_byte_long_name(void)
{
// The longest name a sender built against the old max_size:40 can emit.
// nanopb halts on string overflow rather than truncating, so this only
// passes while the wire-facing meshtastic_User stays 40 wide.
uint8_t buf[64];
size_t len = makeUserPayload(buf, 39);
meshtastic_User u = meshtastic_User_init_zero;
TEST_ASSERT_TRUE(pb_decode_from_bytes(buf, len, &meshtastic_User_msg, &u));
TEST_ASSERT_EQUAL_INT(39, (int)strlen(u.long_name));
// ...and the store boundary clamps it to the local cap.
meshtastic_NodeInfoLite lite = meshtastic_NodeInfoLite_init_default;
TypeConversions::CopyUserToNodeInfoLite(&lite, u);
TEST_ASSERT_EQUAL_INT(MAX_LONG_NAME_BYTES, (int)strlen(lite.long_name));
}
void test_wire_decode_rejects_name_beyond_wire_limit(void)
{
// 45 bytes exceeds even the 40-byte wire buffer; the whole message is
// rejected (documents the hard outer bound).
uint8_t buf[64];
size_t len = makeUserPayload(buf, 45);
meshtastic_User u = meshtastic_User_init_zero;
TEST_ASSERT_FALSE(pb_decode_from_bytes(buf, len, &meshtastic_User_msg, &u));
}
// ---------- short_name truncation --------------------------------------------
void test_short_name_passes_through(void)
@@ -383,6 +427,8 @@ void setup()
RUN_TEST(test_long_name_truncates_when_too_long);
RUN_TEST(test_long_name_round_trip_to_wire);
RUN_TEST(test_long_name_truncated_utf8_boundary_sanitized);
RUN_TEST(test_wire_decode_accepts_legacy_39_byte_long_name);
RUN_TEST(test_wire_decode_rejects_name_beyond_wire_limit);
RUN_TEST(test_short_name_passes_through);
RUN_TEST(test_short_name_truncates_when_too_long);
RUN_TEST(test_bitfield_is_licensed_round_trip);
+47
View File
@@ -163,6 +163,47 @@ void test_above_max_codepoint()
TEST_ASSERT_TRUE(sanitizeUtf8(buf, sizeof(buf)));
}
// --- clampLongName: local 24-byte cap over wider wire buffers ---
void test_clamp_long_name_short_unchanged()
{
char buf[40] = "Kevin Hester";
clampLongName(buf);
TEST_ASSERT_EQUAL_STRING("Kevin Hester", buf);
}
void test_clamp_long_name_exact_cap_unchanged()
{
char buf[40] = "abcdefghijklmnopqrstuvwx"; // exactly 24 bytes
clampLongName(buf);
TEST_ASSERT_EQUAL_STRING("abcdefghijklmnopqrstuvwx", buf);
}
void test_clamp_long_name_truncates_39_bytes()
{
char buf[40];
memset(buf, 'a', 39);
buf[39] = '\0';
clampLongName(buf);
TEST_ASSERT_EQUAL_INT(MAX_LONG_NAME_BYTES, (int)strlen(buf));
}
void test_clamp_long_name_fixes_partial_rune_at_cut()
{
// 22 ASCII then a 4-byte emoji straddling the 24-byte boundary
char buf[40];
memset(buf, 'a', 22);
buf[22] = '\xF0';
buf[23] = '\x9F';
buf[24] = '\x8C';
buf[25] = '\x99';
buf[26] = '\0';
clampLongName(buf);
TEST_ASSERT_EQUAL_INT(24, (int)strlen(buf));
TEST_ASSERT_EQUAL_INT('?', buf[22]);
TEST_ASSERT_EQUAL_INT('?', buf[23]);
}
void setup()
{
UNITY_BEGIN();
@@ -191,6 +232,12 @@ void setup()
RUN_TEST(test_valid_max_codepoint);
RUN_TEST(test_above_max_codepoint);
// clampLongName
RUN_TEST(test_clamp_long_name_short_unchanged);
RUN_TEST(test_clamp_long_name_exact_cap_unchanged);
RUN_TEST(test_clamp_long_name_truncates_39_bytes);
RUN_TEST(test_clamp_long_name_fixes_partial_rune_at_cut);
exit(UNITY_END());
}