TC-SM-1.2: Use correct data type (#31644)

* TC-SM-1.2: Use correct data type

Credit to Manjunath for finding this.

Fixes: https://github.com/project-chip/matter-test-scripts/issues/105

* one more fix

* one more

* Pull this out and add a test

* linter

* add docstring
diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py
index 446907f..409ae97 100644
--- a/src/python_testing/TC_DeviceBasicComposition.py
+++ b/src/python_testing/TC_DeviceBasicComposition.py
@@ -29,7 +29,7 @@
                                     async_test_body, default_matter_test_main)
 from mobly import asserts
 from taglist_and_topology_test_support import (create_device_type_list_for_root, create_device_type_lists, find_tag_list_problems,
-                                               find_tree_roots, get_all_children, get_direct_children_of_root, parts_list_cycles,
+                                               find_tree_roots, flat_list_ok, get_direct_children_of_root, parts_list_cycles,
                                                separate_endpoint_types)
 
 
@@ -554,13 +554,10 @@
         ok = True
         for endpoint_id in flat:
             # ensure that every sub-id in the parts list is included in the parent
-            sub_children = []
-            for child in self.endpoints[endpoint_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]:
-                sub_children.update(get_all_children(child))
-            if not all(item in sub_children for item in self.endpoints[endpoint_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]):
+            if not flat_list_ok(endpoint_id, self.endpoints):
                 location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=attribute_id)
                 self.record_error(self.get_test_name(), location=location,
-                                  problem='Flat parts list does not include all the sub-parts', spec_location='Endpoint composition')
+                                  problem='Flat parts list does not exactly match sub-parts', spec_location='Endpoint composition')
                 ok = False
         if not ok:
             self.fail_current_test()
diff --git a/src/python_testing/TestMatterTestingSupport.py b/src/python_testing/TestMatterTestingSupport.py
index 2ed2907..56f105b 100644
--- a/src/python_testing/TestMatterTestingSupport.py
+++ b/src/python_testing/TestMatterTestingSupport.py
@@ -28,7 +28,7 @@
                                     utc_time_in_matter_epoch)
 from mobly import asserts, signals
 from taglist_and_topology_test_support import (TagProblem, create_device_type_list_for_root, create_device_type_lists,
-                                               find_tag_list_problems, find_tree_roots, get_all_children,
+                                               find_tag_list_problems, find_tree_roots, flat_list_ok, get_all_children,
                                                get_direct_children_of_root, parts_list_cycles, separate_endpoint_types)
 
 
@@ -304,6 +304,14 @@
         cycles = parts_list_cycles(tree, endpoints)
         asserts.assert_equal(cycles, [2, 3, 4, 5, 9, 10, 13, 14, 16])
 
+    def test_flat_list(self):
+        endpoints = self.create_example_topology()
+        # check the aggregator endpoint to ensure it's ok - aggregator is on 11
+        asserts.assert_true(flat_list_ok(11, endpoints), "Incorrect failure on flat list")
+        # Remove one of the sub-children endpoints from the parts list - it should fail
+        endpoints[11][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList].remove(14)
+        asserts.assert_false(flat_list_ok(11, endpoints), "Incorrect pass on flat list missing a part list entry")
+
     def test_get_all_children(self):
         endpoints = self.create_example_topology()
         asserts.assert_equal(get_all_children(2, endpoints), {1, 3, 4, 5, 9}, "Child list for ep2 is incorrect")
diff --git a/src/python_testing/taglist_and_topology_test_support.py b/src/python_testing/taglist_and_topology_test_support.py
index af3bb05..bf5c085 100644
--- a/src/python_testing/taglist_and_topology_test_support.py
+++ b/src/python_testing/taglist_and_topology_test_support.py
@@ -189,3 +189,11 @@
                                                         missing_feature=missing_feature, duplicates=endpoints)
 
     return tag_problems
+
+
+def flat_list_ok(flat_endpoint_id_to_check: int, endpoints_dict: dict[int, Any]) -> bool:
+    '''Checks if the (flat) PartsList on the supplied endpoint contains all the sub-children of its parts.'''
+    sub_children = set()
+    for child in endpoints_dict[flat_endpoint_id_to_check][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]:
+        sub_children.update(get_all_children(child, endpoints_dict))
+    return all(item in endpoints_dict[flat_endpoint_id_to_check][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList] for item in sub_children)