#include #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)); } 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); return UNITY_END(); }