diff --git a/CHANGELOG.md b/CHANGELOG.md index 00d1ce31..0f643588 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ The git repositories are hosted at the following sites: * * -## [Unreleased] - 2026-03-25 +## [Unreleased] - 2026-03-27 ### Security @@ -53,6 +53,8 @@ The git repositories are hosted at the following sites: ### Added +* Added structured-view object subordinate-list add, remove, exist, same + API for interfacing as a list. Added purge API for unit testing. (#1283) * Added ports/pico for Raspberry Pi Pico port of the BACnet stack supporting both BACnet/IP and BACnet MS/TP. (#1232) * Added new functions for duplicating and copying octet string buffers. diff --git a/src/bacnet/basic/object/structured_view.c b/src/bacnet/basic/object/structured_view.c index 9cee412b..b5ddef43 100644 --- a/src/bacnet/basic/object/structured_view.c +++ b/src/bacnet/basic/object/structured_view.c @@ -17,17 +17,9 @@ #include "bacnet/bacdef.h" /* BACnet Stack API */ #include "bacnet/bacdcode.h" -#include "bacnet/bacerror.h" #include "bacnet/bacapp.h" -#include "bacnet/bactext.h" -#include "bacnet/apdu.h" -#include "bacnet/npdu.h" -#include "bacnet/abort.h" #include "bacnet/proplist.h" -#include "bacnet/property.h" -#include "bacnet/reject.h" #include "bacnet/rp.h" -#include "bacnet/basic/services.h" #include "bacnet/basic/sys/keylist.h" /* me! */ #include "structured_view.h" @@ -419,7 +411,7 @@ Structured_View_Subordinate_List_Size(struct object_data *pObject) * @return pointer to the Subordinate_List element */ static BACNET_SUBORDINATE_DATA * -Structured_View_Subordinate_List_Element_Add(OS_Keylist list, KEY key) +Subordinate_List_Element_Add(OS_Keylist list, KEY key) { BACNET_SUBORDINATE_DATA *element = NULL; int index; @@ -441,8 +433,7 @@ Structured_View_Subordinate_List_Element_Add(OS_Keylist list, KEY key) * @brief For a given object element, free the Subordinate_List element * @param element - pointer to the Subordinate_List element */ -static void -Structured_View_Subordinate_List_Element_Remove(OS_Keylist list, KEY key) +static void Subordinate_List_Element_Remove(OS_Keylist list, KEY key) { BACNET_SUBORDINATE_DATA *element; @@ -459,7 +450,7 @@ Structured_View_Subordinate_List_Element_Remove(OS_Keylist list, KEY key) * @brief For a given object instance-number, free the Subordinate_List * @param pObject - pointer to the object data */ -static void Structured_View_Subordinate_List_Free(struct object_data *pObject) +static void Subordinate_List_Purge(struct object_data *pObject) { KEY key = 0; int count = 0; @@ -467,14 +458,161 @@ static void Structured_View_Subordinate_List_Free(struct object_data *pObject) if (pObject) { count = Keylist_Count(pObject->Subordinate_List); while (count > 0) { - Structured_View_Subordinate_List_Element_Remove( - pObject->Subordinate_List, key); + Subordinate_List_Element_Remove(pObject->Subordinate_List, key); key++; count--; } } } +/** + * @brief For a given object instance-number, returns the number of + * Subordinate_List elements + * @param object_instance - object-instance number of the object + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @return Subordinate_List element or NULL if not found + */ +static BACNET_SUBORDINATE_DATA *Subordinate_List_Element( + struct object_data *pObject, BACNET_ARRAY_INDEX array_index) +{ + BACNET_SUBORDINATE_DATA *subordinate_list = NULL; + KEY key = 0; + + if (pObject) { + key = array_index; + subordinate_list = Keylist_Data(pObject->Subordinate_List, key); + } + + return subordinate_list; +} + +/** + * @brief For a given object instance-number, determine if an element exists + * in the Subordinate_List + * @param object_instance - object-instance number of the object + * @param element - pointer to the Subordinate_List element to be checked + * @return array index of the element if it exists, + * or BACNET_ARRAY_ALL if not found + */ +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Exist( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element) +{ + struct object_data *pObject; + BACNET_SUBORDINATE_DATA *list_element; + unsigned count = 0; + BACNET_ARRAY_INDEX array_index = BACNET_ARRAY_ALL; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + if (element) { + count = Structured_View_Subordinate_List_Size(pObject); + for (array_index = 0; array_index < count; array_index++) { + list_element = Subordinate_List_Element(pObject, array_index); + if (Structured_View_Subordinate_List_Element_Same( + list_element, element)) { + break; + } + } + if (array_index >= count) { + array_index = BACNET_ARRAY_ALL; + } + } + } + + return array_index; +} + +/** + * @brief For a given object instance-number, add a unique element to the + * Subordinate_List + * @param object_instance - object-instance number of the object + * @param element - pointer to the Subordinate_List element to be added + * @return array index of the element if it was added successfully, + * or BACNET_ARRAY_ALL if not added + */ +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Add( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element) +{ + struct object_data *pObject; + BACNET_ARRAY_INDEX array_index = BACNET_ARRAY_ALL; + KEY key = 0; + BACNET_SUBORDINATE_DATA *data = NULL; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + if (element) { + /* does this element already exist in the list? */ + array_index = Structured_View_Subordinate_List_Element_Exist( + object_instance, element); + if (array_index == BACNET_ARRAY_ALL) { + /* append a copy of the element to the list */ + key = Keylist_Next_Empty_Key(pObject->Subordinate_List, 0); + data = Subordinate_List_Element_Add( + pObject->Subordinate_List, key); + if (!data) { + array_index = BACNET_ARRAY_ALL; + } else { + memmove(data, element, sizeof(BACNET_SUBORDINATE_DATA)); + if (element->Annotation) { + data->Annotation = bacnet_strdup(element->Annotation); + } + data->next = NULL; + array_index = key; + } + } + } + } + + return array_index; +} + +/** + * @brief For a given object instance-number, remove an element from the + * Subordinate_List + * @param object_instance - object-instance number of the object + * @param element - pointer to the Subordinate_List element to be removed + * @return array index of the element if it was removed successfully, + * or BACNET_ARRAY_ALL if not removed + */ +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Remove( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element) +{ + BACNET_ARRAY_INDEX array_index = BACNET_ARRAY_ALL; + struct object_data *pObject; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + array_index = Structured_View_Subordinate_List_Element_Exist( + object_instance, element); + if (array_index != BACNET_ARRAY_ALL) { + Subordinate_List_Element_Remove( + pObject->Subordinate_List, array_index); + } + } + + return array_index; +} + +/** + * @brief For a given object instance-number, free the Subordinate_List + * @param object_instance - object-instance number of the object + * @return true if the Subordinate_List was purged successfully + */ +bool Structured_View_Subordinate_List_Purge(uint32_t object_instance) +{ + bool status = false; + struct object_data *pObject; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + Subordinate_List_Purge(pObject); + status = true; + } + + return status; +} + /** * @brief For a given object instance-number, resize the Subordinate_List * @param pObject - pointer to the object data @@ -496,16 +634,15 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_List_Resize( /* free the elements at the tail of the list */ key = new_array_size; while (key < old_array_size) { - Structured_View_Subordinate_List_Element_Remove( - pObject->Subordinate_List, key); + Subordinate_List_Element_Remove(pObject->Subordinate_List, key); key++; } } else if (new_array_size > old_array_size) { /* extend the list */ key = old_array_size; while (key < new_array_size) { - element = Structured_View_Subordinate_List_Element_Add( - pObject->Subordinate_List, key); + element = + Subordinate_List_Element_Add(pObject->Subordinate_List, key); if (!element) { error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; break; @@ -517,28 +654,6 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_List_Resize( return error_code; } -/** - * @brief For a given object instance-number, returns the number of - * Subordinate_List elements - * @param object_instance - object-instance number of the object - * @param array_index [in] array index requested: - * 0 to N for individual array members - * @return Subordinate_List element or NULL if not found - */ -static BACNET_SUBORDINATE_DATA *Structured_View_Subordinate_List_Element( - struct object_data *pObject, BACNET_ARRAY_INDEX array_index) -{ - BACNET_SUBORDINATE_DATA *subordinate_list = NULL; - KEY key = 0; - - if (pObject) { - key = array_index; - subordinate_list = Keylist_Data(pObject->Subordinate_List, key); - } - - return subordinate_list; -} - /** * @brief Decode a BACnetARRAY property element to determine the length * @param object_instance [in] BACnet network port object instance number @@ -595,8 +710,7 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_List_Member_Write( len = bacnet_device_object_reference_decode( apdu, apdu_size, &reference); if (len > 0) { - element = Structured_View_Subordinate_List_Element( - pObject, array_index); + element = Subordinate_List_Element(pObject, array_index); if (element) { element->Device_Instance = reference.deviceIdentifier.instance; @@ -674,8 +788,7 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_Annotation_Member_Write( apdu, apdu_size, &annotation); if (len > 0) { if (characterstring_utf8_valid(&annotation)) { - element = Structured_View_Subordinate_List_Element( - pObject, array_index); + element = Subordinate_List_Element(pObject, array_index); if (element) { annotation_string = characterstring_utf8_strdup(&annotation); @@ -761,8 +874,7 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_Node_Type_Member_Write( if (node_type > BACNET_NODE_TYPE_MAX) { error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } else { - element = Structured_View_Subordinate_List_Element( - pObject, array_index); + element = Subordinate_List_Element(pObject, array_index); if (element) { element->Node_Type = node_type; error_code = ERROR_CODE_SUCCESS; @@ -837,8 +949,7 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_Relationship_Member_Write( if (relationship > BACNET_RELATIONSHIP_PROPRIETARY_MAX) { error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } else { - element = Structured_View_Subordinate_List_Element( - pObject, array_index); + element = Subordinate_List_Element(pObject, array_index); if (element) { element->Relationship = relationship; error_code = ERROR_CODE_SUCCESS; @@ -855,6 +966,48 @@ static BACNET_ERROR_CODE Structured_View_Subordinate_Relationship_Member_Write( return error_code; } +/** + * @brief For a given object instance-number, returns the Subordinate_List + * as a linked list with next pointers properly set + * @param object_instance - object-instance number of the object + * @return pointer to the first element of the Subordinate_List, or NULL + */ +BACNET_SUBORDINATE_DATA * +Structured_View_Subordinate_List(uint32_t object_instance) +{ + struct object_data *pObject; + BACNET_SUBORDINATE_DATA *first_element = NULL; + BACNET_SUBORDINATE_DATA *element; + BACNET_SUBORDINATE_DATA *prev_element = NULL; + unsigned int count = 0; + unsigned int i = 0; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + count = Structured_View_Subordinate_List_Size(pObject); + if (count > 0) { + /* Iterate through all elements and set up next pointers */ + for (i = 0; i < count; i++) { + element = Subordinate_List_Element(pObject, i); + if (element) { + if (i == 0) { + /* First element */ + first_element = element; + } else if (prev_element) { + /* Link previous element to current element */ + prev_element->next = element; + } + /* Clear the next pointer for the current element */ + element->next = NULL; + prev_element = element; + } + } + } + } + + return first_element; +} + /** * @brief For a given object instance-number, sets the Subordinate_List * @param object_instance - object-instance number of the object @@ -869,13 +1022,12 @@ void Structured_View_Subordinate_List_Set( pObject = Keylist_Data(Object_List, object_instance); if (pObject) { - Structured_View_Subordinate_List_Free(pObject); + Subordinate_List_Purge(pObject); /* walk the linked list and add to Keylist */ - key = 0; element = subordinate_list; while (element) { - data = Structured_View_Subordinate_List_Element_Add( - pObject->Subordinate_List, key); + key = Keylist_Next_Empty_Key(pObject->Subordinate_List, 0); + data = Subordinate_List_Element_Add(pObject->Subordinate_List, key); if (data) { memmove(data, element, sizeof(BACNET_SUBORDINATE_DATA)); if (element->Annotation) { @@ -884,11 +1036,45 @@ void Structured_View_Subordinate_List_Set( data->next = NULL; } element = element->next; - key++; } } } +/** + * @brief For a given object instance-number, determine if two + * BACNET_SUBORDINATE_DATA elements are the same + * @param element1 - pointer to the first Subordinate_List element + * @param element2 - pointer to the second Subordinate_List element + * @return true if the contents of the elements are the same, false otherwise + */ +bool Structured_View_Subordinate_List_Element_Same( + BACNET_SUBORDINATE_DATA *element1, BACNET_SUBORDINATE_DATA *element2) +{ + if (element1 == element2) { + return true; + } + if (!element1 || !element2) { + return false; + } + if (element1->Device_Instance != element2->Device_Instance || + element1->Object_Type != element2->Object_Type || + element1->Object_Instance != element2->Object_Instance || + element1->Node_Type != element2->Node_Type || + element1->Relationship != element2->Relationship) { + return false; + } + if (element1->Annotation && element2->Annotation) { + if (strcmp(element1->Annotation, element2->Annotation) != 0) { + return false; + } + } else if (element1->Annotation || element2->Annotation) { + /* one is NULL and the other is not */ + return false; + } + + return true; +} + /** * @brief Convert an array of BACnetSubordinateData to linked list * @param array pointer to element zero of the array @@ -1028,8 +1214,7 @@ BACNET_SUBORDINATE_DATA *Structured_View_Subordinate_List_Member( pObject = Keylist_Data(Object_List, object_instance); if (pObject) { - element = - Structured_View_Subordinate_List_Element(pObject, array_index); + element = Subordinate_List_Element(pObject, array_index); } return element; @@ -1628,7 +1813,7 @@ static void Structured_View_Object_Free(struct object_data *pObject) free(pObject->Description); free(pObject->Node_Subtype); free(pObject->Object_Name); - Structured_View_Subordinate_List_Free(pObject); + Subordinate_List_Purge(pObject); Keylist_Delete(pObject->Subordinate_List); free(pObject); } diff --git a/src/bacnet/basic/object/structured_view.h b/src/bacnet/basic/object/structured_view.h index 23b6d89e..0e8e71d0 100644 --- a/src/bacnet/basic/object/structured_view.h +++ b/src/bacnet/basic/object/structured_view.h @@ -98,10 +98,24 @@ BACNET_STACK_EXPORT void Structured_View_Subordinate_List_Link_Array( BACNET_SUBORDINATE_DATA *array, size_t size); BACNET_STACK_EXPORT +bool Structured_View_Subordinate_List_Element_Same( + BACNET_SUBORDINATE_DATA *element1, BACNET_SUBORDINATE_DATA *element2); +BACNET_STACK_EXPORT BACNET_SUBORDINATE_DATA *Structured_View_Subordinate_List_Member( uint32_t object_instance, BACNET_ARRAY_INDEX array_index); BACNET_STACK_EXPORT unsigned int Structured_View_Subordinate_List_Count(uint32_t object_instance); +BACNET_STACK_EXPORT +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Exist( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element); +BACNET_STACK_EXPORT +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Add( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element); +BACNET_STACK_EXPORT +BACNET_ARRAY_INDEX Structured_View_Subordinate_List_Element_Remove( + uint32_t object_instance, BACNET_SUBORDINATE_DATA *element); +BACNET_STACK_EXPORT +bool Structured_View_Subordinate_List_Purge(uint32_t object_instance); BACNET_STACK_EXPORT BACNET_RELATIONSHIP diff --git a/test/bacnet/basic/object/structured_view/src/main.c b/test/bacnet/basic/object/structured_view/src/main.c index e114b12d..ec32ecac 100644 --- a/test/bacnet/basic/object/structured_view/src/main.c +++ b/test/bacnet/basic/object/structured_view/src/main.c @@ -31,6 +31,220 @@ static void Structured_View_Subordinate_List_Member_Same( strcmp(list_member_a->Annotation, list_member_b->Annotation), 0, NULL); } +/** + * @brief Test Structured_View_Subordinate_List_Element_Same + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_list_element_same) +#else +static void test_subordinate_list_element_same(void) +#endif +{ + bool status = false; + BACNET_SUBORDINATE_DATA element_a = { 0, + OBJECT_ANALOG_INPUT, + 1, + "annotation-a", + BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, + NULL }; + BACNET_SUBORDINATE_DATA element_b = { 0, + OBJECT_ANALOG_INPUT, + 1, + "annotation-a", + BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, + NULL }; + BACNET_SUBORDINATE_DATA element_c = { 1, + OBJECT_BINARY_INPUT, + 2, + "annotation-c", + BACNET_NODE_COLLECTION, + BACNET_RELATIONSHIP_DEFAULT, + NULL }; + + /* identical elements */ + status = + Structured_View_Subordinate_List_Element_Same(&element_a, &element_b); + zassert_true(status, NULL); + + /* different elements */ + status = + Structured_View_Subordinate_List_Element_Same(&element_a, &element_c); + zassert_false(status, NULL); + + /* NULL element1 */ + status = Structured_View_Subordinate_List_Element_Same(NULL, &element_b); + zassert_false(status, NULL); + + /* NULL element2 */ + status = Structured_View_Subordinate_List_Element_Same(&element_a, NULL); + zassert_false(status, NULL); + + /* both NULL - returns true (both match "nothing") */ + status = Structured_View_Subordinate_List_Element_Same(NULL, NULL); + zassert_true(status, NULL); + + /* NULL vs non-NULL annotation */ + element_b.Annotation = NULL; + status = + Structured_View_Subordinate_List_Element_Same(&element_a, &element_b); + zassert_false(status, NULL); +} + +/** + * @brief Test Structured_View_Subordinate_List_Element_Exist, + * Structured_View_Subordinate_List_Element_Add, and + * Structured_View_Subordinate_List_Element_Remove + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST( + tests_object_structured_view, + test_subordinate_list_element_add_remove_exist) +#else +static void test_subordinate_list_element_add_remove_exist(void) +#endif +{ + const uint32_t instance = 456; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_SUBORDINATE_DATA element_a = { + 0, OBJECT_ACCUMULATOR, 10, + "watts", BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA element_b = { + 0, OBJECT_LOAD_CONTROL, 20, + "demand", BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA element_not_added = { + 99, OBJECT_BINARY_INPUT, 99, + "not-added", BACNET_NODE_UNKNOWN, BACNET_RELATIONSHIP_DEFAULT, + NULL + }; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* --- Structured_View_Subordinate_List_Element_Add --- */ + + /* add first element - should succeed and return index 0 */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element_a); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* add second element - should succeed */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element_b); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* adding a duplicate should return the existing index, not BACNET_ARRAY_ALL + */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element_a); + zassert_equal(array_index, 0, NULL); + + /* count should be 2 after adding two unique elements */ + zassert_equal(Structured_View_Subordinate_List_Count(instance), 2, NULL); + + /* --- Structured_View_Subordinate_List_Element_Exist --- */ + + /* element_a should be found at index 0 */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &element_a); + zassert_equal(array_index, 0, NULL); + + /* element_b should be found at index 1 */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &element_b); + zassert_equal(array_index, 1, NULL); + + /* element not in the list should return BACNET_ARRAY_ALL */ + array_index = Structured_View_Subordinate_List_Element_Exist( + instance, &element_not_added); + zassert_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* invalid instance should return BACNET_ARRAY_ALL */ + array_index = Structured_View_Subordinate_List_Element_Exist( + instance + 1000, &element_a); + zassert_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* --- Structured_View_Subordinate_List_Element_Remove --- */ + + /* remove element_a */ + array_index = + Structured_View_Subordinate_List_Element_Remove(instance, &element_a); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* element_a should no longer be found */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &element_a); + zassert_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* count should now be 1 */ + zassert_equal(Structured_View_Subordinate_List_Count(instance), 1, NULL); + + /* removing an element that doesn't exist should return BACNET_ARRAY_ALL */ + array_index = Structured_View_Subordinate_List_Element_Remove( + instance, &element_not_added); + zassert_equal(array_index, BACNET_ARRAY_ALL, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test Structured_View_Subordinate_List_Purge + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_list_purge) +#else +static void test_subordinate_list_purge(void) +#endif +{ + const uint32_t instance = 789; + bool status = false; + BACNET_SUBORDINATE_DATA test_subordinate_data[] = { + { 0, OBJECT_ACCUMULATOR, 1, "watts", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_LOAD_CONTROL, 2, "demand", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_CHANNEL, 3, "scene", BACNET_NODE_COLLECTION, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + }; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* populate the list */ + Structured_View_Subordinate_List_Link_Array( + test_subordinate_data, ARRAY_SIZE(test_subordinate_data)); + Structured_View_Subordinate_List_Set(instance, &test_subordinate_data[0]); + zassert_equal( + Structured_View_Subordinate_List_Count(instance), + ARRAY_SIZE(test_subordinate_data), NULL); + + /* purge - all elements should be gone */ + status = Structured_View_Subordinate_List_Purge(instance); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + /* purge on invalid instance returns false */ + status = Structured_View_Subordinate_List_Purge(instance + 1000); + zassert_false(status, NULL); + + /* re-populate after purge to confirm the list is reusable */ + Structured_View_Subordinate_List_Link_Array( + test_subordinate_data, ARRAY_SIZE(test_subordinate_data)); + Structured_View_Subordinate_List_Set(instance, &test_subordinate_data[0]); + zassert_equal( + Structured_View_Subordinate_List_Count(instance), + ARRAY_SIZE(test_subordinate_data), NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + /** * @brief Test */ @@ -161,6 +375,641 @@ static void test_object_structured_view(void) Structured_View_Cleanup(); } +/** + * @brief Test Structured_View_Property_Lists + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_property_lists) +#else +static void test_property_lists(void) +#endif +{ + const int32_t *required = NULL; + const int32_t *optional = NULL; + const int32_t *proprietary = NULL; + + /* all three pointers populated */ + Structured_View_Property_Lists(&required, &optional, &proprietary); + zassert_not_null(required, NULL); + zassert_not_null(optional, NULL); + zassert_not_null(proprietary, NULL); + + /* required list must contain PROP_OBJECT_IDENTIFIER (-1 terminated) */ + { + const int32_t *p = required; + bool found_oid = false; + bool found_name = false; + bool found_node_type = false; + bool found_sublist = false; + while (*p != -1) { + if (*p == PROP_OBJECT_IDENTIFIER) { + found_oid = true; + } + if (*p == PROP_OBJECT_NAME) { + found_name = true; + } + if (*p == PROP_NODE_TYPE) { + found_node_type = true; + } + if (*p == PROP_SUBORDINATE_LIST) { + found_sublist = true; + } + p++; + } + zassert_true(found_oid, NULL); + zassert_true(found_name, NULL); + zassert_true(found_node_type, NULL); + zassert_true(found_sublist, NULL); + } + + /* NULL pointers - must not crash */ + Structured_View_Property_Lists(NULL, NULL, NULL); + Structured_View_Property_Lists(&required, NULL, NULL); + Structured_View_Property_Lists(NULL, &optional, NULL); + Structured_View_Property_Lists(NULL, NULL, &proprietary); +} + +/** + * @brief Test Structured_View_Subordinate_List (raw head-pointer accessor) + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_list) +#else +static void test_subordinate_list(void) +#endif +{ + const uint32_t instance = 321; + BACNET_SUBORDINATE_DATA *head = NULL; + BACNET_SUBORDINATE_DATA list[] = { + { 0, OBJECT_ANALOG_INPUT, 1, "ai-1", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_ANALOG_OUTPUT, 2, "ao-2", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + }; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* before population the list is empty */ + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + Structured_View_Subordinate_List_Link_Array(list, ARRAY_SIZE(list)); + Structured_View_Subordinate_List_Set(instance, &list[0]); + + /* Structured_View_Subordinate_List returns the head of the internal list */ + head = Structured_View_Subordinate_List(instance); + zassert_not_null(head, NULL); + zassert_equal(head->Object_Type, OBJECT_ANALOG_INPUT, NULL); + zassert_equal(head->Object_Instance, 1, NULL); + + /* invalid instance returns NULL */ + zassert_is_null(Structured_View_Subordinate_List(instance + 9999), NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test the four subordinate element encode functions + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_encode_functions) +#else +static void test_subordinate_encode_functions(void) +#endif +{ + const uint32_t instance = 654; + uint8_t apdu[256]; + int len = 0; + BACNET_SUBORDINATE_DATA list[] = { + { 1234, OBJECT_ANALOG_INPUT, 7, "energy", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_BINARY_INPUT, 3, "status", BACNET_NODE_COLLECTION, + BACNET_RELATIONSHIP_DEFAULT, NULL }, + }; + + Structured_View_Init(); + Structured_View_Create(instance); + Structured_View_Subordinate_List_Link_Array(list, ARRAY_SIZE(list)); + Structured_View_Subordinate_List_Set(instance, &list[0]); + + /* --- Structured_View_Subordinate_List_Element_Encode --- */ + + /* valid index 0 - should produce a positive length */ + len = Structured_View_Subordinate_List_Element_Encode(instance, 0, apdu); + zassert_true(len > 0, NULL); + + /* valid index 1 */ + len = Structured_View_Subordinate_List_Element_Encode(instance, 1, apdu); + zassert_true(len > 0, NULL); + + /* out-of-range index returns BACNET_STATUS_ERROR */ + len = Structured_View_Subordinate_List_Element_Encode(instance, 99, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* NULL apdu (length-only query) for index 0 */ + len = Structured_View_Subordinate_List_Element_Encode(instance, 0, NULL); + zassert_true(len > 0, NULL); + + /* --- Structured_View_Subordinate_Annotations_Element_Encode --- */ + + len = Structured_View_Subordinate_Annotations_Element_Encode( + instance, 0, apdu); + zassert_true(len > 0, NULL); + + len = Structured_View_Subordinate_Annotations_Element_Encode( + instance, 1, apdu); + zassert_true(len > 0, NULL); + + /* out-of-range */ + len = Structured_View_Subordinate_Annotations_Element_Encode( + instance, 99, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* --- Structured_View_Subordinate_Node_Types_Element_Encode --- */ + + len = Structured_View_Subordinate_Node_Types_Element_Encode( + instance, 0, apdu); + zassert_true(len > 0, NULL); + + len = Structured_View_Subordinate_Node_Types_Element_Encode( + instance, 1, apdu); + zassert_true(len > 0, NULL); + + /* out-of-range */ + len = Structured_View_Subordinate_Node_Types_Element_Encode( + instance, 99, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* --- Structured_View_Subordinate_Relationships_Element_Encode --- */ + + len = Structured_View_Subordinate_Relationships_Element_Encode( + instance, 0, apdu); + zassert_true(len > 0, NULL); + + len = Structured_View_Subordinate_Relationships_Element_Encode( + instance, 1, apdu); + zassert_true(len > 0, NULL); + + /* out-of-range */ + len = Structured_View_Subordinate_Relationships_Element_Encode( + instance, 99, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test encode functions with invalid instance + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_encode_functions_invalid_instance) +#else +static void test_encode_functions_invalid_instance(void) +#endif +{ + const uint32_t invalid_instance = 9999; + uint8_t apdu[256]; + int len = 0; + + Structured_View_Init(); + + /* All encode functions should return BACNET_STATUS_ERROR for invalid + * instance */ + + /* --- Subordinate_List_Element_Encode --- */ + len = Structured_View_Subordinate_List_Element_Encode( + invalid_instance, 0, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + len = Structured_View_Subordinate_List_Element_Encode( + invalid_instance, 0, NULL); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* --- Subordinate_Annotations_Element_Encode --- */ + len = Structured_View_Subordinate_Annotations_Element_Encode( + invalid_instance, 0, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + len = Structured_View_Subordinate_Annotations_Element_Encode( + invalid_instance, 0, NULL); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* --- Subordinate_Node_Types_Element_Encode --- */ + len = Structured_View_Subordinate_Node_Types_Element_Encode( + invalid_instance, 0, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + len = Structured_View_Subordinate_Node_Types_Element_Encode( + invalid_instance, 0, NULL); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + /* --- Subordinate_Relationships_Element_Encode --- */ + len = Structured_View_Subordinate_Relationships_Element_Encode( + invalid_instance, 0, apdu); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + len = Structured_View_Subordinate_Relationships_Element_Encode( + invalid_instance, 0, NULL); + zassert_equal(len, BACNET_STATUS_ERROR, NULL); + + Structured_View_Cleanup(); +} + +/** + * @brief Test NULL annotation handling in subordinate list elements + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_null_annotations) +#else +static void test_subordinate_null_annotations(void) +#endif +{ + const uint32_t instance = 555; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_SUBORDINATE_DATA element_with_annotation = { + 0, + OBJECT_ACCUMULATOR, + 10, + "has-annotation", + BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA element_null_annotation = { + 0, OBJECT_ACCUMULATOR, 10, + NULL, BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA *test_member = NULL; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* Add element with annotation */ + array_index = Structured_View_Subordinate_List_Element_Add( + instance, &element_with_annotation); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* Retrieve and verify annotation is preserved */ + test_member = Structured_View_Subordinate_List_Member(instance, 0); + zassert_not_null(test_member, NULL); + zassert_not_null(test_member->Annotation, NULL); + + /* Add element with NULL annotation */ + array_index = Structured_View_Subordinate_List_Element_Add( + instance, &element_null_annotation); + /* Should succeed with different annotation */ + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* Verify NULL annotation is preserved */ + test_member = Structured_View_Subordinate_List_Member(instance, 1); + zassert_not_null(test_member, NULL); + zassert_is_null(test_member->Annotation, NULL); + + zassert_equal(Structured_View_Subordinate_List_Count(instance), 2, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test boundary conditions for subordinate list operations + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_list_boundaries) +#else +static void test_subordinate_list_boundaries(void) +#endif +{ + const uint32_t instance = 888; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_SUBORDINATE_DATA element = { + 0, OBJECT_ACCUMULATOR, 1, + "test", BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA *test_member = NULL; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* Test accessing beyond list boundaries */ + test_member = Structured_View_Subordinate_List_Member(instance, 0); + zassert_is_null(test_member, NULL); /* Empty list */ + + test_member = Structured_View_Subordinate_List_Member(instance, 100); + zassert_is_null(test_member, NULL); /* Out of bounds */ + + /* Add one element */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* Access valid index */ + test_member = Structured_View_Subordinate_List_Member(instance, 0); + zassert_not_null(test_member, NULL); + + /* Access index just beyond valid range */ + test_member = Structured_View_Subordinate_List_Member(instance, 1); + zassert_is_null(test_member, NULL); + + /* Test count after operations */ + zassert_equal(Structured_View_Subordinate_List_Count(instance), 1, NULL); + + /* Remove element and verify count */ + array_index = + Structured_View_Subordinate_List_Element_Remove(instance, &element); + zassert_not_equal(array_index, BACNET_STATUS_ERROR, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test sequential add-remove-add cycles + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_sequential_add_remove_cycles) +#else +static void test_sequential_add_remove_cycles(void) +#endif +{ + const uint32_t instance = 777; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_SUBORDINATE_DATA element1 = { + 0, OBJECT_ACCUMULATOR, 1, + "element-1", BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + BACNET_SUBORDINATE_DATA element2 = { + 0, OBJECT_LOAD_CONTROL, 2, + "element-2", BACNET_NODE_MEMBER, BACNET_RELATIONSHIP_CONTAINS, + NULL + }; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* Add element (should succeed) */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element1); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + unsigned count1 = Structured_View_Subordinate_List_Count(instance); + zassert_equal(count1, 1, NULL); + + /* Remove element (should succeed) */ + array_index = + Structured_View_Subordinate_List_Element_Remove(instance, &element1); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* Add another element */ + array_index = + Structured_View_Subordinate_List_Element_Add(instance, &element2); + zassert_not_equal(array_index, BACNET_ARRAY_ALL, NULL); + unsigned count2 = Structured_View_Subordinate_List_Count(instance); + zassert_equal(count2, 1, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test public API functions handle invalid instances gracefully + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_invalid_instance_validation) +#else +static void test_invalid_instance_validation(void) +#endif +{ + const uint32_t invalid_instance = 5000; + char test_string[] = "test"; + BACNET_DEVICE_OBJECT_REFERENCE test_ref = { { OBJECT_DEVICE, 1 }, + { OBJECT_DEVICE, 1 } }; + + Structured_View_Init(); + + /* Valid instance check should return false for invalid instance */ + bool is_valid = Structured_View_Valid_Instance(invalid_instance); + zassert_false(is_valid, NULL); + + /* Operations on invalid instance should handle gracefully (not crash) */ + /* These calls should not crash or cause undefined behavior */ + (void)Structured_View_Subordinate_List_Count(invalid_instance); + (void)Structured_View_Subordinate_List_Member(invalid_instance, 0); + (void)Structured_View_Name_ASCII(invalid_instance); + (void)Structured_View_Description(invalid_instance); + (void)Structured_View_Node_Subtype(invalid_instance); + (void)Structured_View_Node_Type(invalid_instance); + (void)Structured_View_Default_Subordinate_Relationship(invalid_instance); + (void)Structured_View_Represents(invalid_instance); + (void)Structured_View_Context_Get(invalid_instance); + + /* Write operations should fail for invalid instance */ + bool result = Structured_View_Name_Set(invalid_instance, test_string); + zassert_false(result, NULL); + + result = Structured_View_Description_Set(invalid_instance, test_string); + zassert_false(result, NULL); + + result = Structured_View_Node_Subtype_Set(invalid_instance, test_string); + zassert_false(result, NULL); + + result = + Structured_View_Node_Type_Set(invalid_instance, BACNET_NODE_MEMBER); + zassert_false(result, NULL); + + result = Structured_View_Default_Subordinate_Relationship_Set( + invalid_instance, BACNET_RELATIONSHIP_CONTAINS); + zassert_false(result, NULL); + + result = Structured_View_Represents_Set(invalid_instance, &test_ref); + zassert_false(result, NULL); + + result = Structured_View_Subordinate_List_Purge(invalid_instance); + zassert_false(result, NULL); + + Structured_View_Cleanup(); +} + +/** + * @brief Test state consistency after purge and re-populate + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_state_consistency_after_purge) +#else +static void test_state_consistency_after_purge(void) +#endif +{ + const uint32_t instance = 999; + bool status = false; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_SUBORDINATE_DATA test_data[] = { + { 0, OBJECT_ACCUMULATOR, 1, "acc-1", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_LOAD_CONTROL, 2, "lc-2", BACNET_NODE_MEMBER, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + { 0, OBJECT_CHANNEL, 3, "ch-3", BACNET_NODE_COLLECTION, + BACNET_RELATIONSHIP_CONTAINS, NULL }, + }; + + Structured_View_Init(); + Structured_View_Create(instance); + + /* Populate list */ + Structured_View_Subordinate_List_Link_Array( + test_data, ARRAY_SIZE(test_data)); + Structured_View_Subordinate_List_Set(instance, &test_data[0]); + zassert_equal( + Structured_View_Subordinate_List_Count(instance), ARRAY_SIZE(test_data), + NULL); + + /* Verify element exists */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &test_data[0]); + zassert_equal(array_index, 0, NULL); + + /* Purge list */ + status = Structured_View_Subordinate_List_Purge(instance); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + /* Verify element no longer exists after purge */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &test_data[0]); + zassert_equal(array_index, BACNET_ARRAY_ALL, NULL); + + /* Re-populate with same data */ + Structured_View_Subordinate_List_Link_Array( + test_data, ARRAY_SIZE(test_data)); + Structured_View_Subordinate_List_Set(instance, &test_data[0]); + zassert_equal( + Structured_View_Subordinate_List_Count(instance), ARRAY_SIZE(test_data), + NULL); + + /* Verify elements are found again */ + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &test_data[0]); + zassert_equal(array_index, 0, NULL); + + array_index = + Structured_View_Subordinate_List_Element_Exist(instance, &test_data[1]); + zassert_equal(array_index, 1, NULL); + + /* Purge again */ + status = Structured_View_Subordinate_List_Purge(instance); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + +/** + * @brief Test Structured_View_Subordinate_List_Resize via Write_Property + * array_index==0 on PROP_SUBORDINATE_LIST and related array properties. + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(tests_object_structured_view, test_subordinate_list_resize) +#else +static void test_subordinate_list_resize(void) +#endif +{ + const uint32_t instance = 1111; + bool status = false; + BACNET_WRITE_PROPERTY_DATA wp_data = { 0 }; + + Structured_View_Init(); + Structured_View_Create(instance); + + wp_data.object_type = OBJECT_STRUCTURED_VIEW; + wp_data.object_instance = instance; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.array_index = 0; /* index 0 means "write the array size" */ + + /* --- grow from 0 to 3 via PROP_SUBORDINATE_LIST --- */ + wp_data.object_property = PROP_SUBORDINATE_LIST; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 3); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 3, NULL); + + /* --- grow from 3 to 5 --- */ + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 5); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 5, NULL); + + /* --- same size (no change) --- */ + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 5); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 5, NULL); + + /* --- shrink from 5 to 2 --- */ + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 2); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 2, NULL); + + /* --- shrink to zero --- */ + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 0); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 0, NULL); + + /* --- resize via PROP_SUBORDINATE_ANNOTATIONS independently --- */ + /* first grow the list so the annotation resize has something to work with + */ + wp_data.object_property = PROP_SUBORDINATE_LIST; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 4); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + + wp_data.object_property = PROP_SUBORDINATE_ANNOTATIONS; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 2); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 2, NULL); + + /* --- resize via PROP_SUBORDINATE_NODE_TYPES --- */ + wp_data.object_property = PROP_SUBORDINATE_NODE_TYPES; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 3); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 3, NULL); + + /* --- resize via PROP_SUBORDINATE_RELATIONSHIPS --- */ + wp_data.object_property = PROP_SUBORDINATE_RELATIONSHIPS; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 1); + status = Structured_View_Write_Property(&wp_data); + zassert_true(status, NULL); + zassert_equal(Structured_View_Subordinate_List_Count(instance), 1, NULL); + + /* --- invalid instance returns false --- */ + wp_data.object_instance = instance + 9999; + wp_data.object_property = PROP_SUBORDINATE_LIST; + wp_data.application_data_len = + encode_application_unsigned(wp_data.application_data, 2); + status = Structured_View_Write_Property(&wp_data); + zassert_false(status, NULL); + + Structured_View_Delete(instance); + Structured_View_Cleanup(); +} + /** * @} */ @@ -172,7 +1021,20 @@ void test_main(void) { ztest_test_suite( tests_object_structured_view, - ztest_unit_test(test_object_structured_view)); + ztest_unit_test(test_object_structured_view), + ztest_unit_test(test_subordinate_list_element_same), + ztest_unit_test(test_subordinate_list_element_add_remove_exist), + ztest_unit_test(test_subordinate_list_purge), + ztest_unit_test(test_property_lists), + ztest_unit_test(test_subordinate_list), + ztest_unit_test(test_subordinate_encode_functions), + ztest_unit_test(test_encode_functions_invalid_instance), + ztest_unit_test(test_subordinate_null_annotations), + ztest_unit_test(test_subordinate_list_boundaries), + ztest_unit_test(test_sequential_add_remove_cycles), + ztest_unit_test(test_invalid_instance_validation), + ztest_unit_test(test_state_consistency_after_purge), + ztest_unit_test(test_subordinate_list_resize)); ztest_run_test_suite(tests_object_structured_view); }