Files
ninlight-w600/test/test_settings.c
T
Michael Sauer 6e9fb09455 test: Settings-Format längentolerant machen, ota_pending ergänzen
read_rec() akzeptiert jetzt Records mit hdr.length <= sizeof(nl_settings_t):
CRC wird nur über die tatsächlich geschriebenen Bytes geprüft, fehlende Felder
bleiben auf 0 (Default). Ein zu langer (unbekannter) Record wird weiter
abgelehnt. Ein durch massive Kürzung "leer" gelesener Record (fade_in_ms,
fade_out_ms und token allesamt 0) fällt komplett auf die Defaults zurück.
Neues Feld ota_pending (nach fade_out_ms) für den kommenden OTA-Ablauf.
2026-09-12 00:55:20 +02:00

155 lines
4.8 KiB
C

#include <string.h>
#include "unity.h"
#include "fake_flash.h"
#include "config/nl_flash_layout.h"
#include "config/nl_settings.h"
#include "light/nl_light_types.h"
#include "util/nl_crc.h"
void setUp(void)
{
fake_flash_reset();
nl_settings_init(NL_FL_SETTINGS_A, NL_FL_SETTINGS_B);
}
void tearDown(void)
{
TEST_ASSERT_EQUAL_UINT(0, fake_flash_dirty_writes);
}
static nl_settings_t sample(const char *name)
{
nl_settings_t s;
nl_settings_defaults(&s);
strcpy(s.wifi_ssid, "ninHome");
strcpy(s.wifi_pass, "secret");
strcpy(s.name, name);
s.auth_all = 1;
s.power_on_behaviour = NL_POB_ON;
s.fade_in_ms = 1200;
return s;
}
static void test_defaults(void)
{
nl_settings_t s;
TEST_ASSERT_FALSE(nl_settings_load(&s));
TEST_ASSERT_EQUAL_STRING("", s.wifi_ssid);
TEST_ASSERT_EQUAL_STRING("aabbccddeeff0011223344", s.token);
TEST_ASSERT_EQUAL_STRING("", s.name);
TEST_ASSERT_EQUAL_UINT8(0, s.auth_all);
TEST_ASSERT_EQUAL_UINT8(NL_POB_LAST, s.power_on_behaviour);
TEST_ASSERT_EQUAL_UINT16(500, s.fade_in_ms);
TEST_ASSERT_EQUAL_UINT16(500, s.fade_out_ms);
}
static void test_save_and_load(void)
{
nl_settings_t in = sample("Wohnzimmer"), out;
TEST_ASSERT_EQUAL_INT(0, nl_settings_save(&in));
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_MEMORY(&in, &out, sizeof in);
}
static void test_alternates_slots(void)
{
nl_settings_t s, out;
s = sample("a"); nl_settings_save(&s);
s = sample("b"); nl_settings_save(&s);
s = sample("c"); nl_settings_save(&s);
TEST_ASSERT_EQUAL_UINT(2, fake_flash_erases[0]);
TEST_ASSERT_EQUAL_UINT(1, fake_flash_erases[1]);
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_STRING("c", out.name);
}
static void test_power_loss_keeps_previous(void)
{
nl_settings_t s = sample("old"), out;
nl_settings_save(&s);
s = sample("new");
fake_flash_fail_after(50);
TEST_ASSERT_NOT_EQUAL(0, nl_settings_save(&s));
fake_flash_fail_after(-1);
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_STRING("old", out.name);
}
static void test_corrupt_newest_falls_back(void)
{
nl_settings_t s, out;
s = sample("first"); nl_settings_save(&s); /* slot A */
s = sample("second"); nl_settings_save(&s); /* slot B */
fake_flash_mem[NL_FL_SETTINGS_B + 40] ^= 0x01;
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_STRING("first", out.name);
}
static void test_load_accepts_shorter_record(void)
{
nl_settings_t in, out;
uint32_t crc;
/* simulate a record written by an older firmware: length = sizeof - 4, payload truncated */
in = sample("alt");
nl_settings_save(&in);
{
uint16_t shorter = (uint16_t)(sizeof(nl_settings_t) - 4);
memcpy(&fake_flash_mem[NL_FL_SETTINGS_A + 6], &shorter, 2); /* header.length */
crc = nl_crc32(0, &fake_flash_mem[NL_FL_SETTINGS_A], 12 + shorter);
memcpy(&fake_flash_mem[NL_FL_SETTINGS_A + 12 + shorter], &crc, 4);
}
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_STRING("alt", out.name);
TEST_ASSERT_EQUAL_STRING("ninHome", out.wifi_ssid);
}
static void test_load_rejects_longer_record(void)
{
nl_settings_t in = sample("x"), out;
uint16_t longer = (uint16_t)(sizeof(nl_settings_t) + 1);
uint32_t crc;
nl_settings_save(&in);
memcpy(&fake_flash_mem[NL_FL_SETTINGS_A + 6], &longer, 2); /* header.length */
/* recompute the CRC over the (bogus, longer) length so the length check itself is
* what rejects the record, not a CRC mismatch left over from the original length */
crc = nl_crc32(0, &fake_flash_mem[NL_FL_SETTINGS_A], 12 + longer);
memcpy(&fake_flash_mem[NL_FL_SETTINGS_A + 12 + longer], &crc, 4);
TEST_ASSERT_FALSE(nl_settings_load(&out)); /* unknown newer layout -> defaults */
}
static void test_ota_pending_default_and_roundtrip(void)
{
nl_settings_t in, out;
TEST_ASSERT_FALSE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_UINT8(0, out.ota_pending);
in = sample("ota");
in.ota_pending = 1;
TEST_ASSERT_EQUAL_INT(0, nl_settings_save(&in));
TEST_ASSERT_TRUE(nl_settings_load(&out));
TEST_ASSERT_EQUAL_UINT8(1, out.ota_pending);
}
static void test_erase(void)
{
nl_settings_t s = sample("x"), out;
nl_settings_save(&s);
TEST_ASSERT_EQUAL_INT(0, nl_settings_erase());
TEST_ASSERT_FALSE(nl_settings_load(&out));
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_defaults);
RUN_TEST(test_save_and_load);
RUN_TEST(test_alternates_slots);
RUN_TEST(test_power_loss_keeps_previous);
RUN_TEST(test_corrupt_newest_falls_back);
RUN_TEST(test_load_accepts_shorter_record);
RUN_TEST(test_load_rejects_longer_record);
RUN_TEST(test_ota_pending_default_and_roundtrip);
RUN_TEST(test_erase);
return UNITY_END();
}