From d3b0a9577b7bf2b198f5d1118d8bf0facc15e76f Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 20 Mar 2026 17:34:00 -0500 Subject: [PATCH] Add lighting_command_refresh() unit test (#1269) * Add lighting_command_refresh() unit test * Add tests for lighting output writable property list and warn relinquish behavior --- test/bacnet/basic/object/lo/src/main.c | 163 +++++++++++++++++- .../basic/sys/lighting_command/src/main.c | 64 ++++++- 2 files changed, 225 insertions(+), 2 deletions(-) diff --git a/test/bacnet/basic/object/lo/src/main.c b/test/bacnet/basic/object/lo/src/main.c index 3847c3a5..e484c714 100644 --- a/test/bacnet/basic/object/lo/src/main.c +++ b/test/bacnet/basic/object/lo/src/main.c @@ -27,6 +27,28 @@ static bool is_float_equal(float x1, float x2) return fabs(x1 - x2) < 0.001; } +/** + * @brief Search for a property identifier in a terminated property list + * @param list pointer to list terminated by -1 + * @param property property identifier to find + * @return true when found in list + */ +static bool property_list_contains(const int32_t *list, int32_t property) +{ + unsigned i; + + if (!list) { + return false; + } + for (i = 0; list[i] != -1; i++) { + if (list[i] == property) { + return true; + } + } + + return false; +} + static float Test_Tracking_Value; /** * @brief Callback for tracking value updates @@ -42,6 +64,141 @@ static void lighting_command_tracking_value_observer( Test_Tracking_Value = value; } +/** + * @brief Test writable property list API + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(lo_tests, testLightingOutputWritablePropertyList) +#else +static void testLightingOutputWritablePropertyList(void) +#endif +{ + const int32_t *properties = NULL; + + Lighting_Output_Writable_Property_List(1, NULL); + Lighting_Output_Writable_Property_List(1, &properties); + zassert_not_null(properties, NULL); + zassert_true( + property_list_contains(properties, PROP_PRESENT_VALUE), + "missing PROP_PRESENT_VALUE"); + zassert_true( + property_list_contains(properties, PROP_LIGHTING_COMMAND), + "missing PROP_LIGHTING_COMMAND"); + zassert_true( + property_list_contains(properties, PROP_EGRESS_TIME), + "missing PROP_EGRESS_TIME"); + zassert_true( + property_list_contains(properties, PROP_TRIM_FADE_TIME), + "missing PROP_TRIM_FADE_TIME"); + zassert_true( + property_list_contains( + properties, PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY), + "missing PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY"); +} + +/** + * @brief Test delayed WARN_OFF path that triggers blink-stop callback + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(lo_tests, testLightingOutputBlinkStop) +#else +static void testLightingOutputBlinkStop(void) +#endif +{ + const uint32_t instance = 321; + const unsigned priority = 8; + BACNET_LIGHTING_IN_PROGRESS in_progress; + float test_real; + bool status; + + Lighting_Output_Init(); + Lighting_Output_Create(instance); + status = Lighting_Output_Blink_Warn_Enable_Set(instance, true); + zassert_true(status, NULL); + status = Lighting_Output_Egress_Time_Set(instance, 1); + zassert_true(status, NULL); + status = + Lighting_Output_Blink_Warn_Feature_Set(instance, 0.0f, 0, UINT16_MAX); + zassert_true(status, NULL); + status = Lighting_Output_Present_Value_Set(instance, 75.0f, priority); + zassert_true(status, NULL); + Lighting_Output_Timer(instance, 10); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 75.0f), NULL); + + status = Lighting_Output_Present_Value_Set( + instance, BACNET_LIGHTING_SPECIAL_VALUE_WARN_OFF, priority); + zassert_true(status, NULL); + Lighting_Output_Timer(instance, 500); + in_progress = Lighting_Output_In_Progress(instance); + zassert_equal(in_progress, BACNET_LIGHTING_OTHER, NULL); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 75.0f), NULL); + + Lighting_Output_Timer(instance, 500); + in_progress = Lighting_Output_In_Progress(instance); + zassert_equal(in_progress, BACNET_LIGHTING_IDLE, NULL); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 0.0f), NULL); + test_real = Lighting_Output_Priority_Array_Value(instance, priority); + zassert_true(is_float_equal(test_real, 0.0f), NULL); + status = Lighting_Output_Priority_Array_Relinquished(instance, priority); + zassert_false(status, NULL); + + status = Lighting_Output_Delete(instance); + zassert_true(status, NULL); + Lighting_Output_Cleanup(); +} + +/** + * @brief Test WARN_RELINQUISH behavior with egress-time configured + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(lo_tests, testLightingOutputWarnRelinquishEgress) +#else +static void testLightingOutputWarnRelinquishEgress(void) +#endif +{ + const uint32_t instance = 322; + const unsigned priority = 8; + BACNET_LIGHTING_IN_PROGRESS in_progress; + float test_real; + bool status; + + Lighting_Output_Init(); + Lighting_Output_Create(instance); + status = Lighting_Output_Blink_Warn_Enable_Set(instance, true); + zassert_true(status, NULL); + status = Lighting_Output_Egress_Time_Set(instance, 1); + zassert_true(status, NULL); + status = + Lighting_Output_Blink_Warn_Feature_Set(instance, 0.0f, 0, UINT16_MAX); + zassert_true(status, NULL); + + status = Lighting_Output_Present_Value_Set(instance, 60.0f, priority); + zassert_true(status, NULL); + Lighting_Output_Timer(instance, 10); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 60.0f), NULL); + status = Lighting_Output_Priority_Array_Relinquished(instance, priority); + zassert_false(status, NULL); + + status = Lighting_Output_Present_Value_Set( + instance, BACNET_LIGHTING_SPECIAL_VALUE_WARN_RELINQUISH, priority); + zassert_true(status, NULL); + Lighting_Output_Timer(instance, 500); + in_progress = Lighting_Output_In_Progress(instance); + zassert_equal(in_progress, BACNET_LIGHTING_IDLE, NULL); + status = Lighting_Output_Priority_Array_Relinquished(instance, priority); + zassert_true(status, NULL); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 0.0f), NULL); + + status = Lighting_Output_Delete(instance); + zassert_true(status, NULL); + Lighting_Output_Cleanup(); +} + /** * @brief Test */ @@ -547,7 +704,11 @@ ZTEST_SUITE(lo_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(lo_tests, ztest_unit_test(testLightingOutput)); + ztest_test_suite( + lo_tests, ztest_unit_test(testLightingOutput), + ztest_unit_test(testLightingOutputWritablePropertyList), + ztest_unit_test(testLightingOutputBlinkStop), + ztest_unit_test(testLightingOutputWarnRelinquishEgress)); ztest_run_test_suite(lo_tests); } diff --git a/test/bacnet/basic/sys/lighting_command/src/main.c b/test/bacnet/basic/sys/lighting_command/src/main.c index f964b476..600ee193 100644 --- a/test/bacnet/basic/sys/lighting_command/src/main.c +++ b/test/bacnet/basic/sys/lighting_command/src/main.c @@ -64,6 +64,24 @@ static bool is_float_equal(float x1, float x2) static uint32_t Test_Blink_End_Key; static BACNET_LIGHTING_OPERATION Test_Blink_End_Operation; static uint8_t Test_Blink_End_Priority; +static uint32_t Refresh_Event_Count; +static uint32_t Refresh_Event_Key; +static float Refresh_Event_Old_Value; +static float Refresh_Event_New_Value; + +/** + * @brief Callback for tracking refresh notifications + * @param key object identifier + * @param old_value previous tracking value + * @param value current tracking value + */ +static void tracking_refresh_value(uint32_t key, float old_value, float value) +{ + Refresh_Event_Count++; + Refresh_Event_Key = key; + Refresh_Event_Old_Value = old_value; + Refresh_Event_New_Value = value; +} /** * @brief Callback that manipulates the value at the specified priority slot @@ -683,6 +701,49 @@ static void test_lighting_command_unit(void) lighting_command_init(NULL); } +/** + * Tests for lighting command refresh operation + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(lighting_command_tests, test_lighting_command_refresh_unit) +#else +static void test_lighting_command_refresh_unit(void) +#endif +{ + BACNET_LIGHTING_COMMAND_DATA data = { 0 }; + struct lighting_command_notification observer = { 0 }; + float target_level = 75.0f; + uint16_t milliseconds = 10; + + lighting_command_init(&data); + data.Key = 42; + observer.callback = tracking_refresh_value; + lighting_command_notification_add(&data, &observer); + + lighting_command_fade_to(&data, target_level, 0); + lighting_command_timer(&data, milliseconds); + zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); + zassert_true(is_float_equal(data.Tracking_Value, target_level), NULL); + + Refresh_Event_Count = 0; + Refresh_Event_Key = 0; + Refresh_Event_Old_Value = 0.0f; + Refresh_Event_New_Value = 0.0f; + lighting_command_refresh(&data); + zassert_equal(Refresh_Event_Count, 1, NULL); + zassert_equal(Refresh_Event_Key, data.Key, NULL); + zassert_true( + is_float_equal(Refresh_Event_Old_Value, target_level), + "Refresh_Event_Old_Value=%f", Refresh_Event_Old_Value); + zassert_true( + is_float_equal(Refresh_Event_New_Value, target_level), + "Refresh_Event_New_Value=%f", Refresh_Event_New_Value); + zassert_true(is_float_equal(data.Tracking_Value, target_level), NULL); + zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); + + lighting_command_refresh(NULL); +} + /** * @} */ @@ -693,7 +754,8 @@ ZTEST_SUITE(lighting_command_tests, NULL, NULL, NULL, NULL, NULL); void test_main(void) { ztest_test_suite( - lighting_command_tests, ztest_unit_test(test_lighting_command_unit)); + lighting_command_tests, ztest_unit_test(test_lighting_command_unit), + ztest_unit_test(test_lighting_command_refresh_unit)); ztest_run_test_suite(lighting_command_tests); }