Files
ninlight-w600/test/test_state_log.c
T

158 lines
4.5 KiB
C

#include <string.h>
#include "unity.h"
#include "fake_flash.h"
#include "config/nl_flash_layout.h"
#include "config/nl_state_log.h"
#include "light/nl_boot_state.h"
static nl_light_state_t st(uint8_t bri)
{
nl_light_state_t s = {true, bri, NL_MODE_COLOR, 10, 20, 30, 3000};
return s;
}
static void reboot(void)
{
nl_state_log_init(NL_FL_STATE_0, NL_FL_STATE_1);
}
void setUp(void)
{
fake_flash_reset();
reboot();
}
void tearDown(void)
{
TEST_ASSERT_EQUAL_UINT(0, fake_flash_dirty_writes);
}
static void test_empty(void)
{
nl_light_state_t s;
TEST_ASSERT_FALSE(nl_state_log_load(&s));
}
static void test_append_and_reload(void)
{
nl_light_state_t in = st(42), out;
in.mode = NL_MODE_WHITE;
in.on = false;
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&in));
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_TRUE(nl_light_state_equal(&in, &out));
}
static void test_equal_state_is_not_written_again(void)
{
nl_light_state_t s = st(42);
nl_state_log_append(&s);
nl_state_log_append(&s);
for (int i = 0; i < 16; i++)
TEST_ASSERT_EQUAL_HEX8(0xFF, fake_flash_mem[NL_FL_STATE_0 + 16 + i]);
}
static void test_wraps_into_second_sector(void)
{
nl_light_state_t s, out;
for (int i = 0; i < 300; i++) {
s = st((uint8_t)(1 + i % 100));
s.r = (uint8_t)i; /* make every entry distinct */
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&s));
}
TEST_ASSERT_EQUAL_UINT(1, fake_flash_erases[NL_FL_STATE_1 / NL_FLASH_SECTOR_SIZE]);
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_TRUE(nl_light_state_equal(&s, &out));
/* keep going after the reboot */
s = st(77);
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&s));
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(77, out.brightness);
}
static void test_wraps_back_to_first_sector(void)
{
nl_light_state_t s, out;
for (int i = 0; i < 600; i++) {
s = st(50);
s.r = (uint8_t)i;
s.g = (uint8_t)(i >> 8);
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&s));
}
TEST_ASSERT_EQUAL_UINT(1, fake_flash_erases[NL_FL_STATE_0 / NL_FLASH_SECTOR_SIZE]);
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_TRUE(nl_light_state_equal(&s, &out));
}
static void test_power_loss_during_append(void)
{
nl_light_state_t a = st(10), b = st(20), c = st(30), out;
nl_state_log_append(&a);
fake_flash_fail_after(5);
TEST_ASSERT_NOT_EQUAL(0, nl_state_log_append(&b));
fake_flash_fail_after(-1);
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(10, out.brightness);
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&c));
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(30, out.brightness);
}
static void test_garbage_in_empty_log_is_erased_first(void)
{
nl_light_state_t s = st(60), out;
fake_flash_mem[NL_FL_STATE_0 + 3] = 0x12; /* leftovers from the old firmware */
reboot();
TEST_ASSERT_FALSE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&s));
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(60, out.brightness);
}
static void test_erase(void)
{
nl_light_state_t s = st(60), out;
nl_state_log_append(&s);
TEST_ASSERT_EQUAL_INT(0, nl_state_log_erase());
TEST_ASSERT_FALSE(nl_state_log_load(&out));
reboot();
TEST_ASSERT_FALSE(nl_state_log_load(&out));
}
static void test_erase_failure_rescans_flash(void)
{
nl_light_state_t old = st(10), new = st(20), out;
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&old));
fake_flash_fail_after(0);
TEST_ASSERT_NOT_EQUAL(0, nl_state_log_erase());
fake_flash_fail_after(-1);
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(10, out.brightness);
TEST_ASSERT_EQUAL_INT(0, nl_state_log_append(&new));
reboot();
TEST_ASSERT_TRUE(nl_state_log_load(&out));
TEST_ASSERT_EQUAL_UINT8(20, out.brightness);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_empty);
RUN_TEST(test_append_and_reload);
RUN_TEST(test_equal_state_is_not_written_again);
RUN_TEST(test_wraps_into_second_sector);
RUN_TEST(test_wraps_back_to_first_sector);
RUN_TEST(test_power_loss_during_append);
RUN_TEST(test_garbage_in_empty_log_is_erased_first);
RUN_TEST(test_erase);
RUN_TEST(test_erase_failure_rescans_flash);
return UNITY_END();
}