Skip to content

Commit

Permalink
Python testing: move PICS functions (#33759)
Browse files Browse the repository at this point in the history
* Python testing: move PICS functions

We're going to need these for some new tooling, so moving them
into their own file to avoid needing to pull in the entirety
of matter_testing_support

Only changes are moves and function renames.

test: TC_pics_checker.py

* Restyled by autopep8

* Restyled by isort

* fix imports

* Hey, I wrote a unit test

Didn't update it though because I forgot it existed. Thanks, CI.

It passes now.

* Restyled by isort

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Jul 25, 2024
1 parent 7e5c281 commit 0262463
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 68 deletions.
25 changes: 5 additions & 20 deletions src/python_testing/TC_pics_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,10 @@
from matter_testing_support import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, FeaturePathLocation,
MatterBaseTest, TestStep, async_test_body, default_matter_test_main)
from mobly import asserts
from pics_support import accepted_cmd_pics_str, attribute_pics_str, feature_pics_str, generated_cmd_pics_str
from spec_parsing_support import build_xml_clusters


def attribute_pics(pics_base: str, id: int) -> str:
return f'{pics_base}.S.A{id:04x}'


def accepted_cmd_pics(pics_base: str, id: int) -> str:
return f'{pics_base}.S.C{id:02x}.Rsp'


def generated_cmd_pics(pics_base: str, id: int) -> str:
return f'{pics_base}.S.C{id:02x}.Tx'


def feature_pics(pics_base: str, bit: int) -> str:
return f'{pics_base}.S.F{bit:02x}'


class TC_PICS_Checker(MatterBaseTest, BasicCompositionTests):
@async_test_body
async def setup_class(self):
Expand All @@ -64,14 +49,14 @@ def _add_pics_for_lists(self, cluster_id: int, attribute_id_of_element_list: Glo
try:
if attribute_id_of_element_list == GlobalAttributeIds.ATTRIBUTE_LIST_ID:
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_ATTRIBUTES[cluster_id]
pics_mapper = attribute_pics
pics_mapper = attribute_pics_str
elif attribute_id_of_element_list == GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID:
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_ACCEPTED_COMMANDS[cluster_id]
pics_mapper = accepted_cmd_pics
pics_mapper = accepted_cmd_pics_str

elif attribute_id_of_element_list == GlobalAttributeIds.GENERATED_COMMAND_LIST_ID:
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_GENERATED_COMMANDS[cluster_id]
pics_mapper = generated_cmd_pics
pics_mapper = generated_cmd_pics_str
else:
asserts.fail("add_pics_for_list function called for non-list attribute")
except KeyError:
Expand Down Expand Up @@ -177,7 +162,7 @@ def test_TC_IDM_10_4(self):
self.record_warning("PICS check", location=location,
problem=f"Unable to parse feature mask {feature_mask} from cluster {cluster}")
continue
pics = feature_pics(pics_base, feature_bit)
pics = feature_pics_str(pics_base, feature_bit)
if feature_mask & feature_map:
required = True
else:
Expand Down
4 changes: 2 additions & 2 deletions src/python_testing/TestMatterTestingSupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
from chip.clusters.Types import Nullable, NullValue
from chip.tlv import uint
from matter_testing_support import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main,
get_wait_seconds_from_set_time, parse_pics, parse_pics_xml, type_matches,
utc_time_in_matter_epoch)
get_wait_seconds_from_set_time, type_matches, utc_time_in_matter_epoch)
from mobly import asserts, signals
from pics_support import parse_pics, parse_pics_xml
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, flat_list_ok, get_all_children,
get_direct_children_of_root, parts_list_cycles, separate_endpoint_types)
Expand Down
47 changes: 1 addition & 46 deletions src/python_testing/matter_testing_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import argparse
import asyncio
import builtins
import glob
import inspect
import json
import logging
Expand All @@ -30,7 +29,6 @@
import sys
import typing
import uuid
import xml.etree.ElementTree as ET
from binascii import hexlify, unhexlify
from dataclasses import asdict as dataclass_asdict
from dataclasses import dataclass, field
Expand Down Expand Up @@ -64,6 +62,7 @@
from mobly import asserts, base_test, signals, utils
from mobly.config_parser import ENV_MOBLY_LOGPATH, TestRunConfig
from mobly.test_runner import TestRunner
from pics_support import read_pics_from_file

try:
from matter_yamltests.hooks import TestRunnerHooks
Expand Down Expand Up @@ -142,50 +141,6 @@ def get_default_paa_trust_store(root_path: pathlib.Path) -> pathlib.Path:
return pathlib.Path.cwd()


def parse_pics(lines: typing.List[str]) -> dict[str, bool]:
pics = {}
for raw in lines:
line, _, _ = raw.partition("#")
line = line.strip()

if not line:
continue

key, _, val = line.partition("=")
val = val.strip()
if val not in ["1", "0"]:
raise ValueError('PICS {} must have a value of 0 or 1'.format(key))

pics[key.strip()] = (val == "1")
return pics


def parse_pics_xml(contents: str) -> dict[str, bool]:
pics = {}
mytree = ET.fromstring(contents)
for pi in mytree.iter('picsItem'):
name = pi.find('itemNumber').text
support = pi.find('support').text
pics[name] = int(json.loads(support.lower())) == 1
return pics


def read_pics_from_file(path: str) -> dict[str, bool]:
""" Reads a dictionary of PICS from a file (ci format) or directory (xml format). """
if os.path.isdir(os.path.abspath(path)):
pics_dict = {}
for filename in glob.glob(f'{path}/*.xml'):
with open(filename, 'r') as f:
contents = f.read()
pics_dict.update(parse_pics_xml(contents))
return pics_dict

else:
with open(path, 'r') as f:
lines = f.readlines()
return parse_pics(lines)


def type_matches(received_value, desired_type):
""" Checks if the value received matches the expected type.
Expand Down
89 changes: 89 additions & 0 deletions src/python_testing/pics_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#
# 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 glob
import json
import os
import typing
import xml.etree.ElementTree as ET


def attribute_pics_str(pics_base: str, id: int) -> str:
return f'{pics_base}.S.A{id:04x}'


def accepted_cmd_pics_str(pics_base: str, id: int) -> str:
return f'{pics_base}.S.C{id:02x}.Rsp'


def generated_cmd_pics_str(pics_base: str, id: int) -> str:
return f'{pics_base}.S.C{id:02x}.Tx'


def feature_pics_str(pics_base: str, bit: int) -> str:
return f'{pics_base}.S.F{bit:02x}'


def server_pics_str(pics_base: str) -> str:
return f'{pics_base}.S'


def client_pics_str(pics_base: str) -> str:
return f'{pics_base}.C'


def parse_pics(lines: typing.List[str]) -> dict[str, bool]:
pics = {}
for raw in lines:
line, _, _ = raw.partition("#")
line = line.strip()

if not line:
continue

key, _, val = line.partition("=")
val = val.strip()
if val not in ["1", "0"]:
raise ValueError('PICS {} must have a value of 0 or 1'.format(key))

pics[key.strip()] = (val == "1")
return pics


def parse_pics_xml(contents: str) -> dict[str, bool]:
pics = {}
mytree = ET.fromstring(contents)
for pi in mytree.iter('picsItem'):
name = pi.find('itemNumber').text
support = pi.find('support').text
pics[name] = int(json.loads(support.lower())) == 1
return pics


def read_pics_from_file(path: str) -> dict[str, bool]:
""" Reads a dictionary of PICS from a file (ci format) or directory (xml format). """
if os.path.isdir(os.path.abspath(path)):
pics_dict = {}
for filename in glob.glob(f'{path}/*.xml'):
with open(filename, 'r') as f:
contents = f.read()
pics_dict.update(parse_pics_xml(contents))
return pics_dict

else:
with open(path, 'r') as f:
lines = f.readlines()
return parse_pics(lines)

0 comments on commit 0262463

Please sign in to comment.