TC-IDM-10.4: Add PWM as aliased cluster (#34259)

* TC-IDM-10.4: Add PWM as aliased cluster

* Update src/python_testing/test_testing/example_pics_xml_basic_info.xml

Co-authored-by: Kiel Oleson <kielo@apple.com>

---------

Co-authored-by: Kiel Oleson <kielo@apple.com>
diff --git a/src/python_testing/spec_parsing_support.py b/src/python_testing/spec_parsing_support.py
index bc36049..c281996 100644
--- a/src/python_testing/spec_parsing_support.py
+++ b/src/python_testing/spec_parsing_support.py
@@ -130,7 +130,8 @@
               0x042F: 'RNCONC',
               0x0071: 'HEPAFREMON',
               0x0072: 'ACFREMON',
-              0x0405: 'RH'}
+              0x0405: 'RH',
+              0x001C: 'PWM'}
 
 
 class ClusterParser:
diff --git a/src/python_testing/test_testing/example_pics_xml_basic_info.xml b/src/python_testing/test_testing/example_pics_xml_basic_info.xml
index 96f1a34..3d488c3 100644
--- a/src/python_testing/test_testing/example_pics_xml_basic_info.xml
+++ b/src/python_testing/test_testing/example_pics_xml_basic_info.xml
@@ -22,6 +22,14 @@
 			<status>O</status>
 			<support>true</support>
 		</picsItem>
+		<!-- This isn't part of basic info, but I want to check a derived cluster PICS -->
+		<picsItem>
+			<itemNumber>LVL.S</itemNumber>
+			<feature>Does the device implement the Level Control Cluster as a server?</feature>
+			<reference>9.1. Role - index.html[pdf]</reference>
+			<status>O</status>
+			<support>true</support>
+		</picsItem>
 	</usage>
 	<!--PIXIT-->
 	<pixit>
diff --git a/src/python_testing/test_testing/test_IDM_10_4.py b/src/python_testing/test_testing/test_IDM_10_4.py
index ccf7134..8634e94 100644
--- a/src/python_testing/test_testing/test_IDM_10_4.py
+++ b/src/python_testing/test_testing/test_IDM_10_4.py
@@ -38,40 +38,48 @@
 def create_read(include_reachable: bool = False, include_max_paths: bool = False, include_vendor_id: bool = True) -> Attribute.AsyncReadTransaction.ReadResponse:
     # Attribute read here is set to match the example_pics_xml_basic_info.xml in this directory
     bi = Clusters.BasicInformation.Attributes
-    attrs = {bi.DataModelRevision: 1,
-             bi.VendorName: 'testVendor',
-             bi.ProductName: 'testProduct',
-             bi.ProductID: 0x8000,
-             bi.NodeLabel: 'label',
-             bi.Location: 'XX',
-             bi.HardwareVersion: 1,
-             bi.HardwareVersionString: 'one',
-             bi.SoftwareVersion: 2,
-             bi.SoftwareVersionString: 'two',
-             bi.ManufacturingDate: 'today',
-             bi.PartNumber: 'three',
-             bi.ProductURL: 'example.com',
-             bi.ProductLabel: 'myProduct',
-             bi.SerialNumber: 'ABCD1234',
-             bi.LocalConfigDisabled: False,
-             bi.UniqueID: 'Hashy-McHashface'}
+    lvl = Clusters.LevelControl.Attributes
+    attrs_bi = {bi.DataModelRevision: 1,
+                bi.VendorName: 'testVendor',
+                bi.ProductName: 'testProduct',
+                bi.ProductID: 0x8000,
+                bi.NodeLabel: 'label',
+                bi.Location: 'XX',
+                bi.HardwareVersion: 1,
+                bi.HardwareVersionString: 'one',
+                bi.SoftwareVersion: 2,
+                bi.SoftwareVersionString: 'two',
+                bi.ManufacturingDate: 'today',
+                bi.PartNumber: 'three',
+                bi.ProductURL: 'example.com',
+                bi.ProductLabel: 'myProduct',
+                bi.SerialNumber: 'ABCD1234',
+                bi.LocalConfigDisabled: False,
+                bi.UniqueID: 'Hashy-McHashface'}
     if include_reachable:
-        attrs[bi.Reachable] = True
+        attrs_bi[bi.Reachable] = True
     if include_max_paths:
-        attrs[bi.MaxPathsPerInvoke] = 2
+        attrs_bi[bi.MaxPathsPerInvoke] = 2
     if include_vendor_id:
-        attrs[bi.VendorID] = 0xFFF1
+        attrs_bi[bi.VendorID] = 0xFFF1
 
-    attrs[bi.AttributeList] = [a.attribute_id for a in attrs.keys()]
-    attrs[bi.AcceptedCommandList] = []
-    attrs[bi.GeneratedCommandList] = []
-    attrs[bi.FeatureMap] = 0
+    attrs_bi[bi.AttributeList] = [a.attribute_id for a in attrs_bi.keys()]
+    attrs_bi[bi.AcceptedCommandList] = []
+    attrs_bi[bi.GeneratedCommandList] = []
+    attrs_bi[bi.FeatureMap] = 0
+
+    attrs_lvl = {}
+    attrs_lvl[lvl.AttributeList] = []
+    attrs_lvl[lvl.AcceptedCommandList] = []
+    attrs_lvl[lvl.GeneratedCommandList] = []
+    attrs_lvl[lvl.FeatureMap] = 0
 
     resp = Attribute.AsyncReadTransaction.ReadResponse({}, [], {})
-    resp.attributes = {0: {Clusters.BasicInformation: attrs}}
+    resp.attributes = {0: {Clusters.BasicInformation: attrs_bi, Clusters.LevelControl: attrs_lvl}}
 
-    tlv_attrs = {a.attribute_id: value for a, value in attrs.items()}
-    resp.tlvAttributes = {0: {Clusters.BasicInformation.id: tlv_attrs}}
+    tlv_attrs_bi = {a.attribute_id: value for a, value in attrs_bi.items()}
+    tlv_attrs_lvl = {a.attribute_id: value for a, value in attrs_lvl.items()}
+    resp.tlvAttributes = {0: {Clusters.BasicInformation.id: tlv_attrs_bi, Clusters.LevelControl.id: tlv_attrs_lvl}}
 
     return resp