From af29c750759b55b4bc6a86f2bd83f65029cb3ca4 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 19 Sep 2025 20:27:26 -0500 Subject: [PATCH] Test/expanded-object-property-write-coverage (#1102) * Expanded test coverage for WriteProperty in objects. * Added common property tests for Lighting Output object and updated CMake configuration --- test/bacnet/basic/object/lo/CMakeLists.txt | 2 + test/bacnet/basic/object/lo/src/main.c | 167 ++++++------------ test/bacnet/basic/object/test/property_test.c | 86 ++++++++- test/bacnet/basic/object/test/property_test.h | 1 + 4 files changed, 139 insertions(+), 117 deletions(-) diff --git a/test/bacnet/basic/object/lo/CMakeLists.txt b/test/bacnet/basic/object/lo/CMakeLists.txt index 80fefc4c..1da83507 100644 --- a/test/bacnet/basic/object/lo/CMakeLists.txt +++ b/test/bacnet/basic/object/lo/CMakeLists.txt @@ -28,6 +28,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object/test ${TST_DIR}/ztest/include ) @@ -71,6 +72,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/secure_connect.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/test/property_test.c ${TST_DIR}/bacnet/basic/object/test/device_mock.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c diff --git a/test/bacnet/basic/object/lo/src/main.c b/test/bacnet/basic/object/lo/src/main.c index 5ee8a64a..371f62b8 100644 --- a/test/bacnet/basic/object/lo/src/main.c +++ b/test/bacnet/basic/object/lo/src/main.c @@ -8,6 +8,7 @@ #include #include #include +#include /** * @addtogroup bacnet_tests @@ -50,15 +51,7 @@ ZTEST(lo_tests, testLightingOutput) static void testLightingOutput(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0, test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - BACNET_APPLICATION_DATA_VALUE value = { 0 }; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; const uint32_t instance = 123; - BACNET_WRITE_PROPERTY_DATA wpdata = { 0 }; bool status = false; unsigned index, count; uint16_t milliseconds = 10; @@ -71,6 +64,7 @@ static void testLightingOutput(void) uint32_t unsigned_value, test_unsigned; unsigned priority, test_priority; BACNET_OBJECT_ID object_id, test_object_id; + const int skip_fail_property_list[] = { -1 }; Lighting_Output_Init(); Lighting_Output_Create(instance); @@ -84,112 +78,28 @@ static void testLightingOutput(void) zassert_equal(count, 1, NULL); test_instance = Lighting_Output_Index_To_Instance(0); zassert_equal(test_instance, instance, NULL); - - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_LIGHTING_OUTPUT; - rpdata.object_instance = instance; - rpdata.array_index = BACNET_ARRAY_ALL; - - Lighting_Output_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) >= 0) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Lighting_Output_Read_Property(&rpdata); - zassert_not_equal( - len, BACNET_STATUS_ERROR, - "property '%s': failed to ReadProperty!\n", - bactext_property_name(rpdata.object_property)); - if (len >= 0) { - test_len = bacapp_decode_known_property( - rpdata.application_data, len, &value, rpdata.object_type, - rpdata.object_property); - if (rpdata.object_property != PROP_PRIORITY_ARRAY) { - zassert_equal( - len, test_len, "property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - /* check WriteProperty properties */ - wpdata.object_type = rpdata.object_type; - wpdata.object_instance = rpdata.object_instance; - wpdata.object_property = rpdata.object_property; - wpdata.array_index = rpdata.array_index; - memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU); - wpdata.application_data_len = len; - wpdata.error_code = ERROR_CODE_SUCCESS; - status = Lighting_Output_Write_Property(&wpdata); - if (!status) { - /* verify WriteProperty property is known */ - zassert_not_equal( - wpdata.error_code, ERROR_CODE_UNKNOWN_PROPERTY, - "property '%s': WriteProperty Unknown!\n", - bactext_property_name(rpdata.object_property)); - } - if (property_list_commandable_member( - wpdata.object_type, wpdata.object_property)) { - wpdata.priority = 16; - status = Lighting_Output_Write_Property(&wpdata); - zassert_true(status, NULL); - wpdata.application_data_len = - encode_application_null(wpdata.application_data); - wpdata.priority = 16; - status = Lighting_Output_Write_Property(&wpdata); - zassert_true(status, NULL); - wpdata.priority = 6; - status = Lighting_Output_Write_Property(&wpdata); - zassert_false(status, NULL); - zassert_equal( - wpdata.error_code, ERROR_CODE_WRITE_ACCESS_DENIED, NULL); - wpdata.priority = 0; - status = Lighting_Output_Write_Property(&wpdata); - zassert_false(status, NULL); - zassert_equal( - wpdata.error_code, ERROR_CODE_VALUE_OUT_OF_RANGE, NULL); - } - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Lighting_Output_Read_Property(&rpdata); - zassert_not_equal( - len, BACNET_STATUS_ERROR, - "property '%s': failed to ReadProperty!\n", - bactext_property_name(rpdata.object_property)); - if (len > 0) { - test_len = bacapp_decode_application_data( - rpdata.application_data, (uint8_t)rpdata.application_data_len, - &value); - zassert_equal( - len, test_len, "property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - /* check WriteProperty properties */ - wpdata.object_type = rpdata.object_type; - wpdata.object_instance = rpdata.object_instance; - wpdata.object_property = rpdata.object_property; - wpdata.array_index = rpdata.array_index; - memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU); - wpdata.application_data_len = len; - wpdata.error_code = ERROR_CODE_SUCCESS; - status = Lighting_Output_Write_Property(&wpdata); - if (!status) { - /* verify WriteProperty property is known */ - zassert_not_equal( - wpdata.error_code, ERROR_CODE_UNKNOWN_PROPERTY, - "property '%s': WriteProperty Unknown!\n", - bactext_property_name(rpdata.object_property)); - } - } - pOptional++; - } - /* check for unsupported property - use ALL */ - rpdata.object_property = PROP_ALL; - len = Lighting_Output_Read_Property(&rpdata); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); - wpdata.object_property = PROP_ALL; - status = Lighting_Output_Write_Property(&wpdata); + /* set the present-value */ + priority = BACNET_MAX_PRIORITY; + status = Lighting_Output_Present_Value_Set(instance, 100.0f, priority); + zassert_true(status, NULL); + test_real = Lighting_Output_Present_Value(instance); + zassert_true(is_float_equal(test_real, 100.0f), NULL); + test_priority = Lighting_Output_Present_Value_Priority(instance); + zassert_equal(priority, test_priority, NULL); + test_real = Lighting_Output_Priority_Array_Value(instance, priority); + zassert_true(is_float_equal(test_real, 100.0f), NULL); + status = Lighting_Output_Priority_Array_Relinquished(instance, priority); zassert_false(status, NULL); + /* perform a general test for RP/WP */ + bacnet_object_properties_read_write_test( + OBJECT_LIGHTING_OUTPUT, instance, Lighting_Output_Property_Lists, + Lighting_Output_Read_Property, Lighting_Output_Write_Property, + skip_fail_property_list); + /* Relinquish the present-value */ + status = Lighting_Output_Present_Value_Relinquish(instance, priority); + zassert_true(status, NULL); + status = Lighting_Output_Priority_Array_Relinquished(instance, priority); + zassert_true(status, NULL); /* check the dimming/ramping/stepping engine*/ Lighting_Output_Timer(instance, milliseconds); /* test the ASCII name get/set */ @@ -208,6 +118,17 @@ static void testLightingOutput(void) zassert_equal(test_name, sample_name, NULL); /* test local control API */ lighting_command.operation = BACNET_LIGHTS_NONE; + /* configure all the lighting command parameters */ + lighting_command.use_fade_time = true; + lighting_command.fade_time = 1; + lighting_command.use_ramp_rate = true; + lighting_command.ramp_rate = 10.0f; + lighting_command.use_step_increment = true; + lighting_command.step_increment = 10.0f; + lighting_command.use_target_level = true; + lighting_command.target_level = 50.0f; + lighting_command.use_priority = true; + lighting_command.priority = 8; do { status = Lighting_Output_Lighting_Command_Set(instance, &lighting_command); @@ -286,6 +207,7 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* WARN_OFF */ real_value = -3.0; priority = 8; Lighting_Output_Present_Value_Set(instance, real_value, priority); @@ -294,6 +216,7 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* RESTORE_ON */ real_value = -4.0; priority = 8; Lighting_Output_Present_Value_Set(instance, real_value, priority); @@ -302,6 +225,7 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* DEFAULT_ON */ real_value = -5.0; priority = 8; Lighting_Output_Present_Value_Set(instance, real_value, priority); @@ -310,6 +234,7 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* TOGGLE_RESTORE */ real_value = -6.0; priority = 8; Lighting_Output_Present_Value_Set(instance, real_value, priority); @@ -318,6 +243,14 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* twice for toggle */ + Lighting_Output_Present_Value_Set(instance, real_value, priority); + Lighting_Output_Timer(instance, 10); + in_progress = Lighting_Output_In_Progress(instance); + zassert_equal( + in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", + bactext_lighting_in_progress(in_progress)); + /* TOGGLE_DEFAULT */ real_value = -7.0; priority = 8; Lighting_Output_Present_Value_Set(instance, real_value, priority); @@ -326,6 +259,14 @@ static void testLightingOutput(void) zassert_equal( in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", bactext_lighting_in_progress(in_progress)); + /* twice for toggle */ + Lighting_Output_Present_Value_Set(instance, real_value, priority); + Lighting_Output_Timer(instance, 10); + in_progress = Lighting_Output_In_Progress(instance); + zassert_equal( + in_progress, BACNET_LIGHTING_IDLE, "in_progress=%s", + bactext_lighting_in_progress(in_progress)); + /* test the in-progress set API */ status = Lighting_Output_In_Progress_Set( instance, BACNET_LIGHTING_NOT_CONTROLLED); in_progress = Lighting_Output_In_Progress(instance); diff --git a/test/bacnet/basic/object/test/property_test.c b/test/bacnet/basic/object/test/property_test.c index aa59132d..d1c5e13d 100644 --- a/test/bacnet/basic/object/test/property_test.c +++ b/test/bacnet/basic/object/test/property_test.c @@ -26,6 +26,7 @@ bool bacnet_object_property_write_test( BACNET_WRITE_PROPERTY_DATA *wp_data, write_property_function write_property, + bool commandable, const int *skip_fail_property_list) { bool status = false; @@ -59,6 +60,42 @@ bool bacnet_object_property_write_test( bactext_error_code_name(wp_data->error_code)); } } + if (commandable) { + wp_data->priority = 16; + status = write_property(wp_data); + zassert_true( + status, "property=%s priority=%d: error code=%s.\n", + bactext_property_name(wp_data->object_property), + wp_data->priority, + bactext_error_code_name(wp_data->error_code)); + wp_data->application_data_len = + encode_application_null(wp_data->application_data); + wp_data->priority = 16; + status = write_property(wp_data); + zassert_true( + status, "property=%s priority=%d: error code=%s.\n", + bactext_property_name(wp_data->object_property), + wp_data->priority, + bactext_error_code_name(wp_data->error_code)); + wp_data->priority = 6; + status = write_property(wp_data); + zassert_false( + status, "property=%s priority=%d: error code=%s.\n", + bactext_property_name(wp_data->object_property), + wp_data->priority, + bactext_error_code_name(wp_data->error_code)); + zassert_equal( + wp_data->error_code, ERROR_CODE_WRITE_ACCESS_DENIED, NULL); + wp_data->priority = 0; + status = write_property(wp_data); + zassert_false( + status, "property=%s priority=%d: error code=%s.\n", + bactext_property_name(wp_data->object_property), + wp_data->priority, + bactext_error_code_name(wp_data->error_code)); + zassert_equal( + wp_data->error_code, ERROR_CODE_VALUE_OUT_OF_RANGE, NULL); + } } return status; @@ -114,7 +151,8 @@ int bacnet_object_property_read_test( int read_len = 0; uint8_t *apdu; bool is_array, is_list; - BACNET_ARRAY_INDEX array_index = 0; + BACNET_UNSIGNED_INTEGER array_size; + BACNET_ARRAY_INDEX array_index = 0, i; BACNET_APPLICATION_DATA_VALUE value = { 0 }; read_len = read_property(rpdata); @@ -183,6 +221,28 @@ int bacnet_object_property_read_test( "property '%s' array_index=0: error code is %s.\n", bactext_property_name(rpdata->object_property), bactext_error_code_name(rpdata->error_code)); + if (read_len > 0) { + /* validate the data from the read request */ + apdu = rpdata->application_data; + apdu_len = read_len; + len = + bacnet_unsigned_application_decode(apdu, apdu_len, &array_size); + zassert_true(len > 0, NULL); + zassert_true( + len == read_len, "property '%s' array_index=0.\n", + bactext_property_name(rpdata->object_property)); + if (array_size > 0) { + for (i = 1; i <= array_size; i++) { + rpdata->array_index = i; + read_len = read_property(rpdata); + zassert_not_equal( + read_len, BACNET_STATUS_ERROR, + "property '%s' array_index=%u: error code is %s.\n", + bactext_property_name(rpdata->object_property), i, + bactext_error_code_name(rpdata->error_code)); + } + } + } } return len; @@ -215,6 +275,7 @@ void bacnet_object_properties_read_write_test( const int *pProprietary = NULL; BACNET_PROPERTY_ID property; int len = 0; + bool commandable = false; bool status = false; /* ReadProperty parameters */ @@ -255,8 +316,16 @@ void bacnet_object_properties_read_write_test( len = bacnet_object_property_read_test( &rpdata, read_property, skip_fail_property_list); bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + commandable = false; + if (property_list_commandable_member( + wpdata.object_type, wpdata.object_property)) { + if (property_lists_member( + pRequired, pOptional, pProprietary, PROP_PRIORITY_ARRAY)) { + commandable = true; + } + } bacnet_object_property_write_test( - &wpdata, write_property, skip_fail_property_list); + &wpdata, write_property, commandable, skip_fail_property_list); pRequired++; } while ((*pOptional) != -1) { @@ -265,8 +334,16 @@ void bacnet_object_properties_read_write_test( len = bacnet_object_property_read_test( &rpdata, read_property, skip_fail_property_list); bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + commandable = false; + if (property_list_commandable_member( + wpdata.object_type, wpdata.object_property)) { + if (property_lists_member( + pRequired, pOptional, pProprietary, PROP_PRIORITY_ARRAY)) { + commandable = true; + } + } bacnet_object_property_write_test( - &wpdata, write_property, skip_fail_property_list); + &wpdata, write_property, commandable, skip_fail_property_list); pOptional++; } while ((*pProprietary) != -1) { @@ -275,8 +352,9 @@ void bacnet_object_properties_read_write_test( len = bacnet_object_property_read_test( &rpdata, read_property, skip_fail_property_list); bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + commandable = false; bacnet_object_property_write_test( - &wpdata, write_property, skip_fail_property_list); + &wpdata, write_property, commandable, skip_fail_property_list); pProprietary++; } /* check for unsupported property - use ALL */ diff --git a/test/bacnet/basic/object/test/property_test.h b/test/bacnet/basic/object/test/property_test.h index ca9fcc63..83812402 100644 --- a/test/bacnet/basic/object/test/property_test.h +++ b/test/bacnet/basic/object/test/property_test.h @@ -39,6 +39,7 @@ int bacnet_object_property_read_test( bool bacnet_object_property_write_test( BACNET_WRITE_PROPERTY_DATA *wpdata, write_property_function write_property, + bool commandable, const int *skip_fail_property_list); void bacnet_object_property_write_parameter_init(