blob: 7d3220417497135d94e4f38138b7d2143dc6c9db [file]
#
# Copyright (c) 2024 Project CHIP Authors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import os
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
from pics_generator_support import map_cluster_name_to_pics_xml, pics_xml_file_list_loader
from matter.testing.pics import (accepted_cmd_pics_str, attribute_pics_str, client_pics_str, event_pics_str, feature_pics_str,
generated_cmd_pics_str, server_pics_str)
# Add the path to python_testing folder, in order to be able to import from matter_testing_support
sys.path.append(os.path.abspath(sys.path[0] + "/../../python_testing"))
from matter.testing.spec_parsing import build_xml_clusters # noqa: E402
def pics_validation(dm_pics, xml_pics):
"""
Validate the PICS codes from DM and XML.
"""
matched_pics_code = list(set(dm_pics) & set(xml_pics))
pics_xml_only_pics_code = list(set(xml_pics) - set(dm_pics))
dm_scrape_only_pics_code = list(set(dm_pics) - set(xml_pics))
if args.verbose and matched_pics_code:
print(f"Matched PICS: {matched_pics_code} ✅")
if pics_xml_only_pics_code:
print(f"PICS XML Only PICS: {pics_xml_only_pics_code} ❌")
if dm_scrape_only_pics_code:
print(f"DM Scrape Only PICS: {dm_scrape_only_pics_code} ❌")
parser = argparse.ArgumentParser()
parser.add_argument('--pics-template', required=True)
parser.add_argument('--dm-xml', required=True)
parser.add_argument('--verbose', action="store_true")
args, unknown = parser.parse_known_args()
xml_template_path_str = args.pics_template
if not xml_template_path_str.endswith('/'):
xml_template_path_str += '/'
print("Build list of PICS XML")
pics_xml_file_list = pics_xml_file_list_loader(xml_template_path_str, True)
print("Build list of spec XML")
xml_clusters, problems = build_xml_clusters(Path(f"{args.dm_xml}/clusters"))
for cluster in xml_clusters:
pics_xml_file_name = map_cluster_name_to_pics_xml(xml_clusters[cluster].name, pics_xml_file_list)
if pics_xml_file_name:
if args.verbose:
print(
f"Found PICS XML file for {xml_clusters[cluster].name} - {pics_xml_file_name} (Provisional: {xml_clusters[cluster].is_provisional}) ✅")
try:
# Open the XML PICS template file
print(f"Open \"{xml_template_path_str}{pics_xml_file_name}\"")
parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True))
tree = ET.parse(f"{xml_template_path_str}{pics_xml_file_name}", parser)
root = tree.getroot()
except ET.ParseError:
print(f"Could not parse \"{pics_xml_file_name}\" ❌")
continue
print(f"PICS Code: {xml_clusters[cluster].pics}")
pics_code = xml_clusters[cluster].pics
if not pics_code:
print(f"No PICS code found for {xml_clusters[cluster].name} ❌")
continue
pics_code_dm_list = [server_pics_str(pics_code), client_pics_str(pics_code)]
pics_code_xml_list = []
usage_node = root.find('usage')
for pics_item in usage_node:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
# Media PICS contains multiple PICS codes so only append if the PICS code is the selected one.
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
pics_code_xml_list.append(item_number_element.text)
else:
pics_code_xml_list.append(item_number_element.text)
pics_validation(pics_code_dm_list, pics_code_xml_list)
# print(f"FeatureMap: {xml_clusters[cluster].feature_map}")
if xml_clusters[cluster].feature_map:
picsXmlFeatureList = []
featureNode = root.find("./clusterSide[@type='Server']/features")
for pics_item in featureNode:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
picsXmlFeatureList.append(item_number_element.text)
else:
picsXmlFeatureList.append(item_number_element.text)
dmScrapeFeatureList = []
for feature in xml_clusters[cluster].feature_map:
# print(f"Feature: {xml_clusters[cluster].feature_map[feature]} - {feature}")
for bit_index in range(0, 32):
if xml_clusters[cluster].feature_map[feature] >> bit_index == 1:
# print(f"DM Scrape - {feature_pics_str(pics_code, bit_index)}")
dmScrapeFeatureList.append(feature_pics_str(pics_code, bit_index))
pics_validation(dmScrapeFeatureList, picsXmlFeatureList)
# print(f"Attributes: {xml_clusters[cluster].attribute_map}")
if xml_clusters[cluster].attribute_map:
picsXmlAttributeList = []
serverAttributesNode = root.find("./clusterSide[@type='Server']/attributes")
for pics_item in serverAttributesNode:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
picsXmlAttributeList.append(item_number_element.text)
else:
picsXmlAttributeList.append(item_number_element.text)
dmScrapeAttributeList = []
for attribute in xml_clusters[cluster].attribute_map:
# print(f"DM Scrape - {attribute_pics_str(pics_code, xml_clusters[cluster].attribute_map[attribute])}")
dmScrapeAttributeList.append(attribute_pics_str(pics_code, xml_clusters[cluster].attribute_map[attribute]))
pics_validation(dmScrapeAttributeList, picsXmlAttributeList)
# print(f"Accepted Commands: {xml_clusters[cluster].accepted_commands}")
if xml_clusters[cluster].accepted_commands:
picsXmlCommandReceivedList = []
serverCommandsNode = root.find("./clusterSide[@type='Server']/commandsReceived")
for pics_item in serverCommandsNode:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
picsXmlCommandReceivedList.append(item_number_element.text)
else:
picsXmlCommandReceivedList.append(item_number_element.text)
dmScrapeCommandReceivedList = []
for command in xml_clusters[cluster].accepted_commands:
# print(f"DM Scrape - {accepted_cmd_pics_str(pics_code, command)}")
dmScrapeCommandReceivedList.append(accepted_cmd_pics_str(pics_code, command))
pics_validation(dmScrapeCommandReceivedList, picsXmlCommandReceivedList)
if xml_clusters[cluster].generated_commands:
picsXmlCommandGeneratedList = []
serverCommandsNode = root.find("./clusterSide[@type='Server']/commandsGenerated")
for pics_item in serverCommandsNode:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
picsXmlCommandGeneratedList.append(item_number_element.text)
else:
picsXmlCommandGeneratedList.append(item_number_element.text)
dmScrapeCommandGeneratedList = []
for command in xml_clusters[cluster].generated_commands:
# print(f"DM Scrape - {generated_cmd_pics_str(pics_code, command)}")
dmScrapeCommandGeneratedList.append(generated_cmd_pics_str(pics_code, command))
pics_validation(dmScrapeCommandGeneratedList, picsXmlCommandGeneratedList)
if xml_clusters[cluster].events:
picsXmlEventList = []
serverEventsNode = root.find("./clusterSide[@type='Server']/events")
for pics_item in serverEventsNode:
item_number_element = pics_item.find('itemNumber')
# print(f"PICS XML - {item_number_element.text}")
if "media" in pics_xml_file_name.lower() or "group communication" in pics_xml_file_name.lower() or "ota software update" in pics_xml_file_name.lower():
if pics_code in item_number_element.text:
picsXmlEventList.append(item_number_element.text)
else:
picsXmlEventList.append(item_number_element.text)
dmScrapeEventList = []
for event in xml_clusters[cluster].events:
# print(f"DM Scrape - {event_pics_str(pics_code, event)}")
dmScrapeEventList.append(event_pics_str(pics_code, event))
pics_validation(dmScrapeEventList, picsXmlEventList)
else:
print(
f"Could not find matching PICS XML file for {xml_clusters[cluster].name} - {xml_clusters[cluster].pics} (Provisional: {xml_clusters[cluster].is_provisional}) ❌")