#include "unity.h" #include "light/nl_boot_state.h" void setUp(void) {} void tearDown(void) {} static nl_light_state_t red_off(void) { nl_light_state_t s = {false, 40, NL_MODE_COLOR, 255, 0, 0, 3000}; return s; } static void test_default_state(void) { nl_light_state_t d = nl_boot_default_state(nl_board_find("evk")); TEST_ASSERT_TRUE(d.on); TEST_ASSERT_EQUAL_UINT8(100, d.brightness); TEST_ASSERT_EQUAL(NL_MODE_WHITE, d.mode); TEST_ASSERT_EQUAL_UINT16(2700, d.ct); TEST_ASSERT_EQUAL_UINT16(2700, nl_boot_default_state(nl_board_find("e27_cw")).ct); } static void test_last_restores_everything(void) { nl_light_state_t last = red_off(); nl_light_state_t s = nl_boot_state(NL_POB_LAST, &last, nl_board_find("evk"), false); TEST_ASSERT_TRUE(nl_light_state_equal(&last, &s)); } static void test_last_without_saved_state_uses_default(void) { const nl_board_t *b = nl_board_find("evk"); nl_light_state_t s = nl_boot_state(NL_POB_LAST, NULL, b, false); nl_light_state_t d = nl_boot_default_state(b); TEST_ASSERT_TRUE(nl_light_state_equal(&d, &s)); } static void test_on_forces_on_with_last_values(void) { nl_light_state_t last = red_off(); nl_light_state_t s = nl_boot_state(NL_POB_ON, &last, nl_board_find("evk"), false); TEST_ASSERT_TRUE(s.on); TEST_ASSERT_EQUAL_UINT8(40, s.brightness); TEST_ASSERT_EQUAL(NL_MODE_COLOR, s.mode); } static void test_off_forces_off(void) { nl_light_state_t last = red_off(); last.on = true; nl_light_state_t s = nl_boot_state(NL_POB_OFF, &last, nl_board_find("evk"), false); TEST_ASSERT_FALSE(s.on); TEST_ASSERT_EQUAL_UINT8(40, s.brightness); } static void test_sanitizes_stored_values(void) { const nl_board_t *b = nl_board_find("e27_cw"); nl_light_state_t last = {true, 0, NL_MODE_COLOR, 1, 2, 3, 9000}; nl_light_state_t s = nl_boot_state(NL_POB_LAST, &last, b, false); TEST_ASSERT_EQUAL_UINT8(100, s.brightness); /* invalid 0 -> 100 */ TEST_ASSERT_EQUAL(NL_MODE_WHITE, s.mode); /* no RGB on this board */ /* Clamped to whatever this board can do. Deliberately read from the board instead of repeating the number: the range itself is nailed down in test_board.c, and this test is about the clamping, not about the constant. */ TEST_ASSERT_EQUAL_UINT16(b->ct_max, s.ct); } /* Spec 8.2: a reboot caused by an OTA is not a power cut - the light comes back effectively as * power_on_behaviour = last, whatever pob says. */ static void test_after_ota_ignores_pob_off(void) { nl_light_state_t last = red_off(); nl_light_state_t s; last.on = true; s = nl_boot_state(NL_POB_OFF, &last, nl_board_find("evk"), true); TEST_ASSERT_TRUE(s.on); TEST_ASSERT_TRUE(nl_light_state_equal(&last, &s)); } static void test_after_ota_ignores_pob_on(void) { nl_light_state_t last = red_off(); /* stored state: off */ nl_light_state_t s = nl_boot_state(NL_POB_ON, &last, nl_board_find("evk"), true); TEST_ASSERT_FALSE(s.on); TEST_ASSERT_TRUE(nl_light_state_equal(&last, &s)); } static void test_after_ota_still_sanitizes(void) { const nl_board_t *b = nl_board_find("e27_cw"); nl_light_state_t last = {true, 200, NL_MODE_COLOR, 1, 2, 3, 9000}; nl_light_state_t s = nl_boot_state(NL_POB_OFF, &last, b, true); TEST_ASSERT_TRUE(s.on); TEST_ASSERT_EQUAL_UINT8(100, s.brightness); TEST_ASSERT_EQUAL(NL_MODE_WHITE, s.mode); TEST_ASSERT_EQUAL_UINT16(b->ct_max, s.ct); } /* Nothing stored (first boot after a migration): there is no "last" to restore, so the normal * power_on_behaviour rules apply even with the flag set. */ static void test_after_ota_without_saved_state_uses_pob(void) { const nl_board_t *b = nl_board_find("evk"); nl_light_state_t s = nl_boot_state(NL_POB_OFF, NULL, b, true); TEST_ASSERT_FALSE(s.on); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_default_state); RUN_TEST(test_last_restores_everything); RUN_TEST(test_last_without_saved_state_uses_default); RUN_TEST(test_on_forces_on_with_last_values); RUN_TEST(test_off_forces_off); RUN_TEST(test_sanitizes_stored_values); RUN_TEST(test_after_ota_ignores_pob_off); RUN_TEST(test_after_ota_ignores_pob_on); RUN_TEST(test_after_ota_still_sanitizes); RUN_TEST(test_after_ota_without_saved_state_uses_pob); return UNITY_END(); }