Merge upstream/dev into observer-firmware-dev

This commit is contained in:
Adam Gessaman committed 2026-08-28 19:45:59 -07:00
commit 99a7e99a2e
73 files changed
+2024 -369

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
#include "helpers/CommonRadioPrefs.h"
#include <stdio.h>
#include <stdlib.h>
// Native serializer tests instantiate NodePrefs, but the full radio CLI source
// depends on target hardware. These two methods are the only out-of-line vtable
// entries the host-side NodePrefs tests require.
bool CommonRadioPrefs::getByKey(const char* key, char* value, size_t max_len) {
if (strcmp(key, "fem_rxgain") == 0) {
snprintf(value, max_len, "%d", (uint32_t)getFEMRxGain());
return true;
}
if (strcmp(key, "fem_txgain") == 0) {
snprintf(value, max_len, "%d", (uint32_t)getFEMTxGain());
return true;
}
return false;
}
bool CommonRadioPrefs::setByKey(const char* key, const char* value) {
if (strcmp(key, "fem_rxgain") == 0) {
setFEMRxGain(atoi(value));
markDirty();
return true;
}
if (strcmp(key, "fem_txgain") == 0) {
setFEMTxGain(atoi(value));
markDirty();
return true;
}
return false;
}
@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include "helpers/ConfigSerializer.h"
#include "helpers/DynamicConfigSerializer.h"
class NativeFileSystem {
public:
@@ -192,6 +193,23 @@ TEST(ConfigSerializer, LoadSerial_IgnoreUnknowns) {
EXPECT_TRUE(match);
}
TEST(DynamicConfigSerializer, GetSet_Basic) {
DynamicConfigSerializer data;
bool s1 = data.setByKey("age", "11");
bool s2 = data.setByKey("name", "Scott");
EXPECT_TRUE(s1 && s2);
char tmp[32];
bool g1 = data.getByKey("age", tmp, 31);
EXPECT_TRUE(g1);
EXPECT_STREQ("11", tmp);
bool g2 = data.getByKey("name", tmp, 31);
EXPECT_TRUE(g2);
EXPECT_STREQ("Scott", tmp);
}
TEST(NodePrefs, FemGainSettingsRoundTrip) {
NodePrefs saved;
saved.radio_fem_rxgain = 0;
@@ -209,11 +227,20 @@ TEST(NodePrefs, FemGainSettingsRoundTrip) {
loaded.radio_fem_rxgain = 1;
loaded.radio_fem_txgain = 0;
ASSERT_TRUE(loaded.loadSerial(input));
ASSERT_TRUE(loaded.loadSerial(input)) << serialised;
EXPECT_EQ(0, loaded.radio_fem_rxgain);
EXPECT_EQ(1, loaded.radio_fem_txgain);
}
TEST(NodePrefs, TxPowerRemainsSignedThroughRadioPrefs) {
NodePrefs prefs;
prefs.tx_power_dbm = -9;
EXPECT_EQ(-9, prefs.getRadioPrefs()->getTxPower());
prefs.getRadioPrefs()->setTxPower(-8);
EXPECT_EQ(-8, prefs.tx_power_dbm);
}
TEST(ConfigSerializer, LoadSerial_KeyDigitsAfterFirstCharacter) {
MockInputStream s("{age:1,flags:2,name:\"ok\",slot1:7}");
TestStruct data;
@@ -231,6 +258,12 @@ TEST(ConfigSerializer, LoadSerial_RejectsLeadingDigitKey) {
EXPECT_FALSE(data.loadSerial(s));
}
TEST(ConfigSerializer, LoadSerial_AcceptsEmptyObject) {
MockInputStream s("{}");
TestStruct data;
EXPECT_TRUE(data.loadSerial(s));
}
// ── /prefs.json compatibility under the strict shape checks ─────────────────
//
// The scalar-vs-object rejection added for /mqtt.json also runs for the plain
@@ -326,6 +359,73 @@ TEST(NodePrefs, ShapeMismatchIsRejectedAndStopsFurtherApplication) {
EXPECT_EQ(9, nested.sf);
}
TEST(DynamicConfigSerializer, Set_Replaces) {
DynamicConfigSerializer data;
bool s1 = data.setByKey("age", "11");
bool s2 = data.setByKey("name", "Scott");
EXPECT_TRUE(s1 && s2);
bool s3 = data.setByKey("age", "333");
EXPECT_TRUE(s3);
char tmp[32];
bool g1 = data.getByKey("age", tmp, 31);
EXPECT_TRUE(g1);
EXPECT_STREQ("333", tmp);
bool g2 = data.getByKey("name", tmp, 31);
EXPECT_TRUE(g2);
EXPECT_STREQ("Scott", tmp);
}
TEST(DynamicConfigSerializer, GetUnknown_Fail) {
DynamicConfigSerializer data;
bool s1 = data.setByKey("age", "11");
EXPECT_TRUE(s1);
char tmp[32];
bool g2 = data.getByKey("name", tmp, 31);
EXPECT_FALSE(g2);
}
TEST(DynamicConfigSerializer, SaveCustom_Basic) {
MockPrintStream s;
DynamicConfigSerializer data;
bool s1 = data.setByKey("age", "11");
bool s2 = data.setByKey("name", "Scott");
EXPECT_TRUE(s1 && s2);
bool success = data.saveSerial(s);
EXPECT_TRUE(success);
auto l = s.getLength();
char tmp[128];
memcpy(tmp, s.getBytes(), l);
tmp[l] = 0;
const char* expect = "{age:\"11\",name:\"Scott\"}";
EXPECT_STREQ(expect, tmp);
}
TEST(DynamicConfigSerializer, LoadCustom_Basic) {
MockInputStream s("{age:\"" TEST_INT_S "\",name:\"Scott\"}");
DynamicConfigSerializer data;
bool success = data.loadSerial(s);
EXPECT_TRUE(success);
char tmp[32];
bool g1 = data.getByKey("age", tmp, 31);
EXPECT_TRUE(g1);
EXPECT_STREQ(TEST_INT_S, tmp);
bool g2 = data.getByKey("name", tmp, 31);
EXPECT_TRUE(g2);
EXPECT_STREQ("Scott", tmp);
}
// ── main ───────────────────────────────────────────────────────
@@ -0,0 +1,34 @@
#include <gtest/gtest.h>
#include <string.h>
#include "MeshCore.h"
class LegacyOTABoard : public mesh::MainBoard {
public:
bool called = false;
uint16_t getBattMilliVolts() override { return 0; }
const char* getManufacturerName() const override { return "test"; }
void reboot() override { }
uint8_t getStartupReason() const override { return BD_STARTUP_NORMAL; }
bool startOTAUpdate(const char* id, char reply[]) override {
called = true;
strcpy(reply, id);
return true;
}
};
TEST(MainBoardAPI, ThreeArgumentOtaFallsBackToLegacyOverride) {
LegacyOTABoard board;
mesh::MainBoard* base = &board;
char reply[16] = { 0 };
EXPECT_TRUE(base->startOTAUpdate("legacy", reply, true));
EXPECT_TRUE(board.called);
EXPECT_STREQ("legacy", reply);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}