mirror of
https://github.com/meshtastic/firmware.git
synced 2026-09-16 00:10:11 -04:00
* Extend userPrefs coverage to the whole channel table and the missing config fields initDefaultChannel() handled only indices 0-2, so USERPREFS_CHANNELS_TO_WRITE above 3 produced live secondary channels carrying the public default PSK; it now covers all eight slots, with bin/platformio-custom.py completing every field of a configured index so indices 0-2 stay byte-identical. Adds USERPREFS_CHANNEL_<n>_IS_MUTED, USERPREFS_CONFIG_DEVICE_REBROADCAST_MODE, USERPREFS_CONFIG_DEVICE_NODE_INFO_BROADCAST_SECS, USERPREFS_CONFIG_LORA_CONFIG_OK_TO_MQTT, USERPREFS_CONFIG_SECURITY_IS_MANAGED and USERPREFS_CANNED_MESSAGES, applied after installRoleDefaults() and validated the way AdminModule validates a set-config. Adds test_userprefs_channels, covering the configured table under coverage-channel-table and the stock defaults under every other env. * Address review: hex channel count, PSK width assert, canned-message termination USERPREFS_CHANNELS_TO_WRITE now parses 0x-prefixed hex, matching the format userPrefs.jsonc documents, without int(x, 0)'s rejection of a leading-zero decimal such as "03". A static_assert rejects a USERPREFS_CHANNEL_<n>_PSK literal wider than psk.bytes, which memcpy would otherwise write over the fields after it. The USERPREFS_CANNED_MESSAGES copy keeps strncpy's zero-padding and terminates explicitly, rather than shortening the length, which would have left the last byte unwritten.
180 lines
6.8 KiB
C++
180 lines
6.8 KiB
C++
// Channels::initDefaults() must populate every index named by USERPREFS_CHANNELS_TO_WRITE, and an
|
|
// index configured in part must keep the firmware's own value for every field left out.
|
|
//
|
|
// Under coverage-channel-table / native-windows-channel-table userprefs_fixture.h is -include'd and
|
|
// the configured cases run; under any other env the suite asserts the stock defaults instead.
|
|
|
|
#include "Channels.h"
|
|
#include "MeshTypes.h" // Include BEFORE TestUtil.h (provides NodeNum, isBroadcast, etc.)
|
|
#include "NodeDB.h" // channelFile
|
|
#include "TestUtil.h"
|
|
#include "mesh-pb-constants.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <unity.h>
|
|
|
|
#if defined(ARCH_PORTDUINO)
|
|
#define UPC_TEST_ENTRY extern "C"
|
|
#else
|
|
#define UPC_TEST_ENTRY
|
|
#endif
|
|
|
|
// The well-known default PSK in its 1-byte short form, i.e. what initDefaultChannel() leaves on an
|
|
// index no userPref touched.
|
|
static const uint8_t kDefaultPskShortForm = 0x01;
|
|
|
|
void setUp(void)
|
|
{
|
|
memset(&channelFile, 0, sizeof(channelFile));
|
|
channels.initDefaults();
|
|
}
|
|
|
|
void tearDown(void) {}
|
|
|
|
static void expectShortFormDefaultPsk(const meshtastic_ChannelSettings &s)
|
|
{
|
|
TEST_ASSERT_EQUAL_UINT(1, s.psk.size);
|
|
TEST_ASSERT_EQUAL_UINT8(kDefaultPskShortForm, s.psk.bytes[0]);
|
|
}
|
|
|
|
// An index initDefaultChannel() wrote but no userPref configured: default PSK, empty name, position
|
|
// sharing off, nothing muted, no MQTT.
|
|
static void expectStockChannel(uint8_t idx)
|
|
{
|
|
const meshtastic_Channel &ch = channels.getByIndex(idx);
|
|
TEST_ASSERT_TRUE(ch.has_settings);
|
|
TEST_ASSERT_TRUE(ch.settings.has_module_settings);
|
|
expectShortFormDefaultPsk(ch.settings);
|
|
TEST_ASSERT_EQUAL_STRING("", ch.settings.name);
|
|
TEST_ASSERT_EQUAL_UINT(0, ch.settings.module_settings.position_precision);
|
|
TEST_ASSERT_FALSE(ch.settings.module_settings.is_muted);
|
|
TEST_ASSERT_FALSE(ch.settings.uplink_enabled);
|
|
TEST_ASSERT_FALSE(ch.settings.downlink_enabled);
|
|
}
|
|
|
|
#ifdef USERPREFS_CHANNELS_TO_WRITE
|
|
|
|
static const uint8_t kChannel0Psk[] = USERPREFS_CHANNEL_0_PSK;
|
|
static const uint8_t kChannel3Psk[] = USERPREFS_CHANNEL_3_PSK;
|
|
|
|
// The bug this table replaces: USERPREFS_CHANNELS_TO_WRITE past 3 produced live secondary channels
|
|
// carrying the public default PSK instead of the vendor's, because initDefaultChannel()'s switch
|
|
// stopped at case 2.
|
|
static void test_index_beyond_two_gets_its_configured_psk()
|
|
{
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(3).settings;
|
|
TEST_ASSERT_EQUAL_UINT(sizeof(kChannel3Psk), s.psk.size);
|
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(kChannel3Psk, s.psk.bytes, sizeof(kChannel3Psk));
|
|
TEST_ASSERT_EQUAL_STRING(USERPREFS_CHANNEL_3_NAME, s.name);
|
|
}
|
|
|
|
static void test_index_zero_matches_its_userprefs()
|
|
{
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(0).settings;
|
|
TEST_ASSERT_EQUAL_UINT(sizeof(kChannel0Psk), s.psk.size);
|
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(kChannel0Psk, s.psk.bytes, sizeof(kChannel0Psk));
|
|
TEST_ASSERT_EQUAL_STRING(USERPREFS_CHANNEL_0_NAME, s.name);
|
|
TEST_ASSERT_EQUAL_UINT(USERPREFS_CHANNEL_0_PRECISION, s.module_settings.position_precision);
|
|
TEST_ASSERT_TRUE(s.module_settings.is_muted);
|
|
TEST_ASSERT_TRUE(s.uplink_enabled);
|
|
TEST_ASSERT_FALSE(s.downlink_enabled);
|
|
}
|
|
|
|
static void test_every_written_index_has_a_role()
|
|
{
|
|
for (int i = 0; i < USERPREFS_CHANNELS_TO_WRITE; i++) {
|
|
const meshtastic_Channel &ch = channels.getByIndex(i);
|
|
TEST_ASSERT_TRUE(ch.has_settings);
|
|
TEST_ASSERT_TRUE(ch.settings.has_module_settings);
|
|
TEST_ASSERT_EQUAL(i == 0 ? meshtastic_Channel_Role_PRIMARY : meshtastic_Channel_Role_SECONDARY, ch.role);
|
|
}
|
|
}
|
|
|
|
// Index 1 is inside CHANNELS_TO_WRITE but has no userPref of its own.
|
|
static void test_unconfigured_index_inside_range_is_stock()
|
|
{
|
|
expectStockChannel(1);
|
|
}
|
|
|
|
// Index 4 sets only a name upstream; the generator fills the rest with the values
|
|
// initDefaultChannel() would otherwise have left in place, so a partial config is not a way to
|
|
// accidentally ship uplink or a raised position precision.
|
|
static void test_partly_configured_index_keeps_firmware_defaults()
|
|
{
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(4).settings;
|
|
TEST_ASSERT_EQUAL_STRING(USERPREFS_CHANNEL_4_NAME, s.name);
|
|
expectShortFormDefaultPsk(s);
|
|
TEST_ASSERT_EQUAL_UINT(0, s.module_settings.position_precision);
|
|
TEST_ASSERT_FALSE(s.module_settings.is_muted);
|
|
TEST_ASSERT_FALSE(s.uplink_enabled);
|
|
TEST_ASSERT_FALSE(s.downlink_enabled);
|
|
}
|
|
|
|
// Indices past USERPREFS_CHANNELS_TO_WRITE are never handed to initDefaultChannel(), so they must
|
|
// stay zeroed rather than picking up a neighbour's key.
|
|
static void test_index_past_channels_to_write_is_untouched()
|
|
{
|
|
for (int i = USERPREFS_CHANNELS_TO_WRITE; i < MAX_NUM_CHANNELS; i++) {
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(i).settings;
|
|
TEST_ASSERT_EQUAL_STRING("", s.name);
|
|
TEST_ASSERT_EQUAL_UINT(0, s.psk.size);
|
|
}
|
|
}
|
|
|
|
// The switch this table replaces used strcpy() into a char[12].
|
|
static void test_over_long_name_is_truncated_and_terminated()
|
|
{
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(2).settings;
|
|
TEST_ASSERT_TRUE(strlen(USERPREFS_CHANNEL_2_NAME) >= sizeof(s.name));
|
|
TEST_ASSERT_EQUAL_UINT(sizeof(s.name) - 1, strlen(s.name));
|
|
TEST_ASSERT_EQUAL_CHAR('\0', s.name[sizeof(s.name) - 1]);
|
|
TEST_ASSERT_EQUAL_MEMORY(USERPREFS_CHANNEL_2_NAME, s.name, sizeof(s.name) - 1);
|
|
}
|
|
|
|
#else // no channel userPrefs: the baseline the table must not have moved
|
|
|
|
static void test_stock_build_writes_only_index_zero()
|
|
{
|
|
expectStockChannel(0);
|
|
TEST_ASSERT_EQUAL(meshtastic_Channel_Role_PRIMARY, channels.getByIndex(0).role);
|
|
for (int i = 1; i < MAX_NUM_CHANNELS; i++) {
|
|
const meshtastic_ChannelSettings &s = channels.getByIndex(i).settings;
|
|
TEST_ASSERT_EQUAL_STRING("", s.name);
|
|
TEST_ASSERT_EQUAL_UINT(0, s.psk.size);
|
|
}
|
|
}
|
|
|
|
static void test_stock_build_fills_the_whole_table()
|
|
{
|
|
TEST_ASSERT_EQUAL_UINT(MAX_NUM_CHANNELS, channelFile.channels_count);
|
|
}
|
|
|
|
#endif
|
|
|
|
UPC_TEST_ENTRY void setup()
|
|
{
|
|
initializeTestEnvironment();
|
|
UNITY_BEGIN();
|
|
|
|
#ifdef USERPREFS_CHANNELS_TO_WRITE
|
|
printf("\n=== channel table beyond index 2 ===\n");
|
|
RUN_TEST(test_index_beyond_two_gets_its_configured_psk);
|
|
RUN_TEST(test_index_zero_matches_its_userprefs);
|
|
RUN_TEST(test_every_written_index_has_a_role);
|
|
|
|
printf("\n=== omitted fields and bounds ===\n");
|
|
RUN_TEST(test_unconfigured_index_inside_range_is_stock);
|
|
RUN_TEST(test_partly_configured_index_keeps_firmware_defaults);
|
|
RUN_TEST(test_index_past_channels_to_write_is_untouched);
|
|
RUN_TEST(test_over_long_name_is_truncated_and_terminated);
|
|
#else
|
|
printf("\n=== stock defaults (no channel userPrefs) ===\n");
|
|
RUN_TEST(test_stock_build_writes_only_index_zero);
|
|
RUN_TEST(test_stock_build_fills_the_whole_table);
|
|
#endif
|
|
|
|
exit(UNITY_END());
|
|
}
|
|
|
|
UPC_TEST_ENTRY void loop() {}
|