/** * @file * @brief Unit test for object * @author Steve Karg * @date July 2023 * @section LICENSE * * @copyright SPDX-License-Identifier: MIT */ #include #include #include #include /** * @addtogroup bacnet_tests * @{ */ static BACNET_WRITE_PROPERTY_DATA Write_Property_Internal_Data; static bool Write_Property_Internal(BACNET_WRITE_PROPERTY_DATA *wp_data) { memcpy( &Write_Property_Internal_Data, wp_data, sizeof(BACNET_WRITE_PROPERTY_DATA)); return true; } static struct channel_write_property_notification Write_Property_Notification; static BACNET_WRITE_PROPERTY_DATA Write_Property_Notification_Data; static uint32_t Write_Property_Notification_Instance; static bool Write_Property_Notification_Status; static void Channel_Write_Property_Notification_Callback( uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data) { Write_Property_Notification_Instance = instance; Write_Property_Notification_Status = status; memcpy( &Write_Property_Notification_Data, wp_data, sizeof(BACNET_WRITE_PROPERTY_DATA)); } /** * @brief Test */ static void test_Channel_Property_Read_Write(void) { const uint32_t instance = 123; unsigned count = 0; unsigned index = 0; const char *sample_name = "Channel:0"; const char *test_name = NULL; uint32_t test_instance = 0; bool status = false; int len = 0; const int32_t skip_fail_property_list[] = { -1 }; BACNET_CHANNEL_VALUE channel_value = { 0 }; BACNET_WRITE_PROPERTY_DATA wp_data = { 0 }; BACNET_WRITE_GROUP_DATA wg_data = { 0 }; BACNET_APPLICATION_DATA_VALUE value = { 0 }; BACNET_APPLICATION_DATA_VALUE test_value = { 0 }; BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE member = { 0 }; Channel_Write_Property_Internal_Callback_Set(Write_Property_Internal); Write_Property_Notification.callback = Channel_Write_Property_Notification_Callback; Write_Property_Notification.next = NULL; Channel_Write_Property_Notification_Add(&Write_Property_Notification); Channel_Init(); Channel_Create(instance); status = Channel_Valid_Instance(instance); zassert_true(status, NULL); status = Channel_Valid_Instance(instance - 1); zassert_false(status, NULL); index = Channel_Instance_To_Index(instance); zassert_equal(index, 0, NULL); test_instance = Channel_Index_To_Instance(index); zassert_equal(instance, test_instance, NULL); count = Channel_Count(); zassert_true(count > 0, NULL); /* configure the instance property values and test API for lists */ member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_ANALOG_OUTPUT; member.objectIdentifier.instance = 1; member.arrayIndex = BACNET_ARRAY_ALL; member.propertyIdentifier = PROP_PRESENT_VALUE; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); status = Channel_Reference_List_Member_Element_Set(instance, index, &member); zassert_true(status, NULL); status = Channel_Control_Groups_Element_Set(instance, 1, 1); zassert_true(status, NULL); member.propertyIdentifier = PROP_RELINQUISH_DEFAULT; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_BINARY_OUTPUT; member.objectIdentifier.instance = 1; member.propertyIdentifier = PROP_PRESENT_VALUE; member.arrayIndex = BACNET_ARRAY_ALL; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_RELINQUISH_DEFAULT; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_MULTI_STATE_OUTPUT; member.objectIdentifier.instance = 1; member.propertyIdentifier = PROP_PRESENT_VALUE; member.arrayIndex = BACNET_ARRAY_ALL; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_RELINQUISH_DEFAULT; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_LIGHTING_OUTPUT; member.objectIdentifier.instance = 1; member.propertyIdentifier = PROP_PRESENT_VALUE; member.arrayIndex = BACNET_ARRAY_ALL; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_RELINQUISH_DEFAULT; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_HIGH_END_TRIM; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_COLOR; member.objectIdentifier.instance = 1; member.propertyIdentifier = PROP_PRESENT_VALUE; member.arrayIndex = BACNET_ARRAY_ALL; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_DEFAULT_COLOR; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.deviceIdentifier.type = OBJECT_DEVICE; member.deviceIdentifier.instance = 0; member.objectIdentifier.type = OBJECT_COLOR_TEMPERATURE; member.objectIdentifier.instance = 1; member.propertyIdentifier = PROP_PRESENT_VALUE; member.arrayIndex = BACNET_ARRAY_ALL; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); member.propertyIdentifier = PROP_DEFAULT_COLOR_TEMPERATURE; index = Channel_Reference_List_Member_Element_Add(instance, &member); zassert_not_equal(index, 0, NULL); /* perform a general test for RP/WP */ bacnet_object_properties_read_write_test( OBJECT_CHANNEL, instance, Channel_Property_Lists, Channel_Read_Property, Channel_Write_Property, skip_fail_property_list); /* test the ASCII name get/set */ status = Channel_Name_Set(instance, sample_name); zassert_true(status, NULL); test_name = Channel_Name_ASCII(instance); zassert_equal(test_name, sample_name, NULL); status = Channel_Name_Set(instance, NULL); zassert_true(status, NULL); test_name = Channel_Name_ASCII(instance); zassert_equal(test_name, NULL, NULL); /* test specific WriteProperty values - common configuration */ wp_data.object_type = OBJECT_CHANNEL; wp_data.object_instance = instance; wp_data.array_index = BACNET_ARRAY_ALL; wp_data.priority = BACNET_MAX_PRIORITY; /* specific WriteProperty value */ wp_data.object_property = PROP_PRESENT_VALUE; value.tag = BACNET_APPLICATION_TAG_CHANNEL_VALUE; value.type.Channel_Value.tag = BACNET_APPLICATION_TAG_REAL; value.type.Channel_Value.type.Real = 3.14159; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); /* does the callback object property match the last member? */ zassert_equal( Write_Property_Internal_Data.object_property, member.propertyIdentifier, "%s:%d %s", bactext_object_type_name(Write_Property_Internal_Data.object_type), Write_Property_Internal_Data.object_instance, bactext_property_name(Write_Property_Internal_Data.object_property)); zassert_equal( Write_Property_Internal_Data.object_type, member.objectIdentifier.type, "WriteProperty=%s:%d", bactext_object_type_name(Write_Property_Internal_Data.object_type), Write_Property_Internal_Data.object_instance); zassert_equal( Write_Property_Internal_Data.object_instance, member.objectIdentifier.instance, "WriteProperty=%s:%d", bactext_object_type_name(Write_Property_Internal_Data.object_type), Write_Property_Internal_Data.object_instance); len = bacapp_decode_application_data( Write_Property_Internal_Data.application_data, Write_Property_Internal_Data.application_data_len, &test_value); zassert_true(len > 0, "len=%d", len); /* does the notify callback object property match the last member? */ zassert_equal(Write_Property_Notification_Instance, instance, NULL); zassert_equal(Write_Property_Notification_Status, true, NULL); zassert_equal( Write_Property_Notification_Data.object_property, member.propertyIdentifier, NULL); zassert_equal( Write_Property_Notification_Data.object_type, member.objectIdentifier.type, "WriteProperty=%s:%d", bactext_object_type_name(Write_Property_Notification_Data.object_type), Write_Property_Notification_Data.object_instance); zassert_equal( Write_Property_Notification_Data.object_instance, member.objectIdentifier.instance, "WriteProperty=%s:%d", bactext_object_type_name(Write_Property_Notification_Data.object_type), Write_Property_Notification_Data.object_instance); len = bacapp_decode_application_data( Write_Property_Notification_Data.application_data, Write_Property_Notification_Data.application_data_len, &test_value); zassert_true(len > 0, "len=%d", len); /* another coercion */ value.type.Channel_Value.tag = BACNET_APPLICATION_TAG_XY_COLOR; value.type.Channel_Value.type.XY_Color.x_coordinate = 0.4590f; value.type.Channel_Value.type.XY_Color.y_coordinate = 0.4101f; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); /* specific WriteProperty value */ wp_data.object_property = PROP_OUT_OF_SERVICE; value.tag = BACNET_APPLICATION_TAG_BOOLEAN; value.type.Boolean = true; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); /* specific WriteProperty value */ wp_data.object_property = PROP_CHANNEL_NUMBER; value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; value.type.Unsigned_Int = 123; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); value.type.Unsigned_Int = UINT16_MAX + 1; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* specific WriteProperty value */ wp_data.object_property = PROP_CONTROL_GROUPS; wp_data.array_index = 1; value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; /* min valid value */ value.type.Unsigned_Int = 0; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); /* max valid value */ value.type.Unsigned_Int = UINT16_MAX; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); /* array size - read-only */ wp_data.array_index = 0; status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* out-of-range value */ wp_data.array_index = 1; value.type.Unsigned_Int = UINT16_MAX + 1; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* invalid data type for Array element */ wp_data.array_index = 1; value.type.Real = 3.14159f; value.tag = BACNET_APPLICATION_TAG_REAL; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* invalid data type for Array size */ wp_data.array_index = 0; status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* invalid array-index - probably */ wp_data.array_index = BACNET_ARRAY_ALL - 1; value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; value.type.Unsigned_Int = 0; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* specific WriteProperty value */ wp_data.array_index = 1; wp_data.priority = BACNET_MAX_PRIORITY; wp_data.object_property = PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES; value.tag = BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE; value.type.Device_Object_Property_Reference.objectIdentifier.type = OBJECT_ANALOG_OUTPUT; value.type.Device_Object_Property_Reference.objectIdentifier.instance = 1; value.type.Device_Object_Property_Reference.propertyIdentifier = PROP_PRESENT_VALUE; value.type.Device_Object_Property_Reference.arrayIndex = BACNET_ARRAY_ALL; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_true(status, NULL); wp_data.array_index = 0; status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); wp_data.array_index = BACNET_ARRAY_ALL - 1; status = Channel_Write_Property(&wp_data); zassert_false(status, NULL); /* read-only property */ wp_data.array_index = BACNET_ARRAY_ALL; wp_data.priority = BACNET_MAX_PRIORITY; wp_data.object_property = PROP_OBJECT_TYPE; value.tag = BACNET_APPLICATION_TAG_ENUMERATED; value.type.Enumerated = OBJECT_ANALOG_INPUT; wp_data.application_data_len = bacapp_encode_application_data(wp_data.application_data, &value); status = Channel_Write_Property(&wp_data); zassert_equal(wp_data.error_class, ERROR_CLASS_PROPERTY, NULL); zassert_equal(wp_data.error_code, ERROR_CODE_WRITE_ACCESS_DENIED, NULL); zassert_false(status, NULL); /* present-value API */ channel_value.tag = BACNET_APPLICATION_TAG_REAL; channel_value.type.Real = 3.14159f; status = Channel_Present_Value_Set(instance, 1, &channel_value); zassert_true(status, NULL); /* context API */ Channel_Context_Set(instance, Channel_Context_Get(instance)); /* WriteGroup API */ wg_data.change_list.channel = 1; wg_data.change_list.overriding_priority = BACNET_MAX_PRIORITY; wg_data.change_list.value.tag = BACNET_APPLICATION_TAG_REAL; wg_data.change_list.value.type.Real = 2.71828f; wg_data.inhibit_delay = 0; wg_data.write_priority = BACNET_MAX_PRIORITY; Channel_Write_Group(&wg_data, 0, &wg_data.change_list); /* cleanup */ status = Channel_Delete(instance); zassert_true(status, NULL); Channel_Cleanup(); } /** * @} */ void test_main(void) { ztest_test_suite( channel_tests, ztest_unit_test(test_Channel_Property_Read_Write)); ztest_run_test_suite(channel_tests); }