Skip to content

Commit 9b7e300

Browse files
Python testing: move PICS functions (#33759)
* 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 <commits@restyled.io>
1 parent d6c29d2 commit 9b7e300

File tree

4 files changed

+97
-68
lines changed

4 files changed

+97
-68
lines changed

src/python_testing/TC_pics_checker.py

+5-20
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,10 @@
2222
from matter_testing_support import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, FeaturePathLocation,
2323
MatterBaseTest, TestStep, async_test_body, default_matter_test_main)
2424
from mobly import asserts
25+
from pics_support import accepted_cmd_pics_str, attribute_pics_str, feature_pics_str, generated_cmd_pics_str
2526
from spec_parsing_support import build_xml_clusters
2627

2728

28-
def attribute_pics(pics_base: str, id: int) -> str:
29-
return f'{pics_base}.S.A{id:04x}'
30-
31-
32-
def accepted_cmd_pics(pics_base: str, id: int) -> str:
33-
return f'{pics_base}.S.C{id:02x}.Rsp'
34-
35-
36-
def generated_cmd_pics(pics_base: str, id: int) -> str:
37-
return f'{pics_base}.S.C{id:02x}.Tx'
38-
39-
40-
def feature_pics(pics_base: str, bit: int) -> str:
41-
return f'{pics_base}.S.F{bit:02x}'
42-
43-
4429
class TC_PICS_Checker(MatterBaseTest, BasicCompositionTests):
4530
@async_test_body
4631
async def setup_class(self):
@@ -64,14 +49,14 @@ def _add_pics_for_lists(self, cluster_id: int, attribute_id_of_element_list: Glo
6449
try:
6550
if attribute_id_of_element_list == GlobalAttributeIds.ATTRIBUTE_LIST_ID:
6651
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_ATTRIBUTES[cluster_id]
67-
pics_mapper = attribute_pics
52+
pics_mapper = attribute_pics_str
6853
elif attribute_id_of_element_list == GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID:
6954
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_ACCEPTED_COMMANDS[cluster_id]
70-
pics_mapper = accepted_cmd_pics
55+
pics_mapper = accepted_cmd_pics_str
7156

7257
elif attribute_id_of_element_list == GlobalAttributeIds.GENERATED_COMMAND_LIST_ID:
7358
all_spec_elements_to_check = Clusters.ClusterObjects.ALL_GENERATED_COMMANDS[cluster_id]
74-
pics_mapper = generated_cmd_pics
59+
pics_mapper = generated_cmd_pics_str
7560
else:
7661
asserts.fail("add_pics_for_list function called for non-list attribute")
7762
except KeyError:
@@ -177,7 +162,7 @@ def test_TC_IDM_10_4(self):
177162
self.record_warning("PICS check", location=location,
178163
problem=f"Unable to parse feature mask {feature_mask} from cluster {cluster}")
179164
continue
180-
pics = feature_pics(pics_base, feature_bit)
165+
pics = feature_pics_str(pics_base, feature_bit)
181166
if feature_mask & feature_map:
182167
required = True
183168
else:

src/python_testing/TestMatterTestingSupport.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
from chip.clusters.Types import Nullable, NullValue
2525
from chip.tlv import uint
2626
from matter_testing_support import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main,
27-
get_wait_seconds_from_set_time, parse_pics, parse_pics_xml, type_matches,
28-
utc_time_in_matter_epoch)
27+
get_wait_seconds_from_set_time, type_matches, utc_time_in_matter_epoch)
2928
from mobly import asserts, signals
29+
from pics_support import parse_pics, parse_pics_xml
3030
from taglist_and_topology_test_support import (TagProblem, create_device_type_list_for_root, create_device_type_lists,
3131
find_tag_list_problems, find_tree_roots, flat_list_ok, get_all_children,
3232
get_direct_children_of_root, parts_list_cycles, separate_endpoint_types)

src/python_testing/matter_testing_support.py

+1-46
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import argparse
1919
import asyncio
2020
import builtins
21-
import glob
2221
import inspect
2322
import json
2423
import logging
@@ -30,7 +29,6 @@
3029
import sys
3130
import typing
3231
import uuid
33-
import xml.etree.ElementTree as ET
3432
from binascii import hexlify, unhexlify
3533
from dataclasses import asdict as dataclass_asdict
3634
from dataclasses import dataclass, field
@@ -64,6 +62,7 @@
6462
from mobly import asserts, base_test, signals, utils
6563
from mobly.config_parser import ENV_MOBLY_LOGPATH, TestRunConfig
6664
from mobly.test_runner import TestRunner
65+
from pics_support import read_pics_from_file
6766

6867
try:
6968
from matter_yamltests.hooks import TestRunnerHooks
@@ -142,50 +141,6 @@ def get_default_paa_trust_store(root_path: pathlib.Path) -> pathlib.Path:
142141
return pathlib.Path.cwd()
143142

144143

145-
def parse_pics(lines: typing.List[str]) -> dict[str, bool]:
146-
pics = {}
147-
for raw in lines:
148-
line, _, _ = raw.partition("#")
149-
line = line.strip()
150-
151-
if not line:
152-
continue
153-
154-
key, _, val = line.partition("=")
155-
val = val.strip()
156-
if val not in ["1", "0"]:
157-
raise ValueError('PICS {} must have a value of 0 or 1'.format(key))
158-
159-
pics[key.strip()] = (val == "1")
160-
return pics
161-
162-
163-
def parse_pics_xml(contents: str) -> dict[str, bool]:
164-
pics = {}
165-
mytree = ET.fromstring(contents)
166-
for pi in mytree.iter('picsItem'):
167-
name = pi.find('itemNumber').text
168-
support = pi.find('support').text
169-
pics[name] = int(json.loads(support.lower())) == 1
170-
return pics
171-
172-
173-
def read_pics_from_file(path: str) -> dict[str, bool]:
174-
""" Reads a dictionary of PICS from a file (ci format) or directory (xml format). """
175-
if os.path.isdir(os.path.abspath(path)):
176-
pics_dict = {}
177-
for filename in glob.glob(f'{path}/*.xml'):
178-
with open(filename, 'r') as f:
179-
contents = f.read()
180-
pics_dict.update(parse_pics_xml(contents))
181-
return pics_dict
182-
183-
else:
184-
with open(path, 'r') as f:
185-
lines = f.readlines()
186-
return parse_pics(lines)
187-
188-
189144
def type_matches(received_value, desired_type):
190145
""" Checks if the value received matches the expected type.
191146

src/python_testing/pics_support.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#
2+
# Copyright (c) 2024 Project CHIP Authors
3+
# All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
import glob
18+
import json
19+
import os
20+
import typing
21+
import xml.etree.ElementTree as ET
22+
23+
24+
def attribute_pics_str(pics_base: str, id: int) -> str:
25+
return f'{pics_base}.S.A{id:04x}'
26+
27+
28+
def accepted_cmd_pics_str(pics_base: str, id: int) -> str:
29+
return f'{pics_base}.S.C{id:02x}.Rsp'
30+
31+
32+
def generated_cmd_pics_str(pics_base: str, id: int) -> str:
33+
return f'{pics_base}.S.C{id:02x}.Tx'
34+
35+
36+
def feature_pics_str(pics_base: str, bit: int) -> str:
37+
return f'{pics_base}.S.F{bit:02x}'
38+
39+
40+
def server_pics_str(pics_base: str) -> str:
41+
return f'{pics_base}.S'
42+
43+
44+
def client_pics_str(pics_base: str) -> str:
45+
return f'{pics_base}.C'
46+
47+
48+
def parse_pics(lines: typing.List[str]) -> dict[str, bool]:
49+
pics = {}
50+
for raw in lines:
51+
line, _, _ = raw.partition("#")
52+
line = line.strip()
53+
54+
if not line:
55+
continue
56+
57+
key, _, val = line.partition("=")
58+
val = val.strip()
59+
if val not in ["1", "0"]:
60+
raise ValueError('PICS {} must have a value of 0 or 1'.format(key))
61+
62+
pics[key.strip()] = (val == "1")
63+
return pics
64+
65+
66+
def parse_pics_xml(contents: str) -> dict[str, bool]:
67+
pics = {}
68+
mytree = ET.fromstring(contents)
69+
for pi in mytree.iter('picsItem'):
70+
name = pi.find('itemNumber').text
71+
support = pi.find('support').text
72+
pics[name] = int(json.loads(support.lower())) == 1
73+
return pics
74+
75+
76+
def read_pics_from_file(path: str) -> dict[str, bool]:
77+
""" Reads a dictionary of PICS from a file (ci format) or directory (xml format). """
78+
if os.path.isdir(os.path.abspath(path)):
79+
pics_dict = {}
80+
for filename in glob.glob(f'{path}/*.xml'):
81+
with open(filename, 'r') as f:
82+
contents = f.read()
83+
pics_dict.update(parse_pics_xml(contents))
84+
return pics_dict
85+
86+
else:
87+
with open(path, 'r') as f:
88+
lines = f.readlines()
89+
return parse_pics(lines)

0 commit comments

Comments
 (0)