Skip to content

Commit 7ebc71f

Browse files
authored
Python testing: id range check functions (#33510)
* Python testing: id range check functions * add test to workflow * use range more directly * change to enums * isort * fix workflow
1 parent f5fad3d commit 7ebc71f

File tree

3 files changed

+324
-1
lines changed

3 files changed

+324
-1
lines changed

.github/workflows/tests.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@ jobs:
561561
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCOPSTATE_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
562562
scripts/run_in_python_env.sh out/venv './src/python_testing/test_testing/test_TC_DA_1_2.py'
563563
scripts/run_in_python_env.sh out/venv './src/python_testing/test_testing/test_TC_ICDM_2_1.py'
564+
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestIdChecks.py'
565+
564566
- name: Uploading core files
565567
uses: actions/upload-artifact@v4
566568
if: ${{ failure() && !env.ACT }}

src/python_testing/TestIdChecks.py

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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+
18+
from global_attribute_ids import (AttributeIdType, ClusterIdType, DeviceTypeIdType, attribute_id_type, cluster_id_type,
19+
device_type_id_type, is_valid_attribute_id, is_valid_cluster_id, is_valid_device_type_id)
20+
from matter_testing_support import MatterBaseTest, default_matter_test_main
21+
from mobly import asserts
22+
23+
24+
class TestIdChecks(MatterBaseTest):
25+
def test_device_type_ids(self):
26+
standard_good = [0x0000_0000, 0x0000_BFFF]
27+
standard_bad = [0x0000_C000]
28+
29+
manufacturer_good = [0x0001_0000, 0x0001_BFFF, 0xFFF0_0000, 0xFFF0_BFFF]
30+
manufacturer_bad = [0x0001_C000, 0xFFF0_C000]
31+
32+
test_good = [0xFFF1_0000, 0xFFF1_BFFF, 0xFFF4_0000, 0xFFF4_BFFF]
33+
test_bad = [0xFFF1_C000, 0xFFF4_C000]
34+
35+
prefix_bad = [0xFFF5_0000, 0xFFF5_BFFFF, 0xFFF5_C000]
36+
37+
def check_standard(id):
38+
id_type = device_type_id_type(id)
39+
msg = f"Incorrect device type range assessment, expecting standard {id:08x}, type = {id_type}"
40+
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kStandard, msg)
41+
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
42+
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=False), msg)
43+
44+
def check_manufacturer(id):
45+
id_type = device_type_id_type(id)
46+
msg = f"Incorrect device type range assessment, expecting manufacturer {id:08x}, type = {id_type}"
47+
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kManufacturer, msg)
48+
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
49+
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=False), msg)
50+
51+
def check_test(id):
52+
id_type = device_type_id_type(id)
53+
msg = f"Incorrect device type range assessment, expecting test {id:08x}, type = {id_type}"
54+
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kTest, msg)
55+
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
56+
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=False), msg)
57+
58+
def check_all_bad(id):
59+
id_type = device_type_id_type(id)
60+
msg = f"Incorrect device type range assessment, expecting invalid {id:08x}, type = {id_type}"
61+
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kInvalid, msg)
62+
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=True), msg)
63+
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=False), msg)
64+
65+
for id in standard_good:
66+
check_standard(id)
67+
68+
for id in standard_bad:
69+
check_all_bad(id)
70+
71+
for id in manufacturer_good:
72+
check_manufacturer(id)
73+
74+
for id in manufacturer_bad:
75+
check_all_bad(id)
76+
77+
for id in test_good:
78+
check_test(id)
79+
80+
for id in test_bad:
81+
check_all_bad(id)
82+
83+
for id in prefix_bad:
84+
check_all_bad(id)
85+
86+
def test_cluster_ids(self):
87+
standard_good = [0x0000_0000, 0x0000_7FFF]
88+
standard_bad = [0x0000_8000]
89+
90+
manufacturer_good = [0x0001_FC00, 0x0001_FFFE, 0xFFF0_FC00, 0xFFF0_FFFE]
91+
manufacturer_bad = [0x0001_0000, 0x0001_7FFF, 0x0001_FFFF, 0xFFF0_0000, 0xFFF0_7FFF, 0xFFF0_FFFF]
92+
93+
test_good = [0xFFF1_FC00, 0xFFF1_FFFE, 0xFFF4_FC00, 0xFFF4_FFFE]
94+
test_bad = [0xFFF1_0000, 0xFFF1_7FFF, 0xFFF1_FFFF, 0xFFF4_0000, 0xFFF4_7FFF, 0xFFF4_FFFF]
95+
96+
prefix_bad = [0xFFF5_0000, 0xFFF5_FC00, 0xFFF5_FFFF]
97+
98+
def check_standard(id):
99+
id_type = cluster_id_type(id)
100+
msg = f"Incorrect cluster range assessment, expecting standard {id:08x}, type = {id_type}"
101+
asserts.assert_equal(id_type, ClusterIdType.kStandard, msg)
102+
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
103+
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=False), msg)
104+
105+
def check_manufacturer(id):
106+
id_type = cluster_id_type(id)
107+
msg = f"Incorrect cluster range assessment, expecting manufacturer {id:08x}, type = {id_type}"
108+
asserts.assert_equal(id_type, ClusterIdType.kManufacturer, msg)
109+
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
110+
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=False), msg)
111+
112+
def check_test(id):
113+
id_type = cluster_id_type(id)
114+
msg = f"Incorrect cluster range assessment, expecting test {id:08x}, type = {id_type}"
115+
asserts.assert_equal(id_type, ClusterIdType.kTest, msg)
116+
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
117+
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=False), msg)
118+
119+
def check_all_bad(id):
120+
id_type = cluster_id_type(id)
121+
msg = f"Incorrect cluster range assessment, expecting invalid {id:08x}, type = {id_type}"
122+
asserts.assert_equal(id_type, ClusterIdType.kInvalid, msg)
123+
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=True), msg)
124+
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=False), msg)
125+
126+
for id in standard_good:
127+
check_standard(id)
128+
129+
for id in standard_bad:
130+
check_all_bad(id)
131+
132+
for id in manufacturer_good:
133+
check_manufacturer(id)
134+
135+
for id in manufacturer_bad:
136+
check_all_bad(id)
137+
138+
for id in test_good:
139+
check_test(id)
140+
141+
for id in test_bad:
142+
check_all_bad(id)
143+
144+
for id in prefix_bad:
145+
check_all_bad(id)
146+
147+
def test_attribute_ids(self):
148+
standard_global_good = [0x0000_F000, 0x0000_FFFE]
149+
standard_global_bad = [0x0000_FFFF]
150+
standard_non_global_good = [0x0000_0000, 0x0000_4FFF]
151+
standard_non_global_bad = [0x0000_5000]
152+
manufacturer_good = [0x0001_0000, 0x0001_4FFF, 0xFFF0_0000, 0xFFF0_4FFF]
153+
manufacturer_bad = [0x0001_5000, 0x0001_F000, 0x0001_FFFFF, 0xFFF0_5000, 0xFFF0_F000, 0xFFF0_FFFF]
154+
test_good = [0xFFF1_0000, 0xFFF1_4FFF, 0xFFF4_0000, 0xFFF4_4FFF]
155+
test_bad = [0xFFF1_5000, 0xFFF1_F000, 0xFFF1_FFFFF, 0xFFF4_5000, 0xFFF4_F000, 0xFFF4_FFFF]
156+
prefix_bad = [0xFFF5_0000, 0xFFF5_4FFF, 0xFFF5_5000, 0xFFF5_F000, 0xFFF5_FFFF]
157+
158+
def check_standard_global(id):
159+
id_type = attribute_id_type(id)
160+
msg = f"Incorrect attribute range assessment, expecting standard global {id:08x}, type = {id_type}"
161+
asserts.assert_equal(id_type, AttributeIdType.kStandardGlobal, msg)
162+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
163+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)
164+
165+
def check_standard_non_global(id):
166+
id_type = attribute_id_type(id)
167+
msg = f"Incorrect attribute range assessment, expecting standard non-global {id:08x}, type = {id_type}"
168+
asserts.assert_equal(id_type, AttributeIdType.kStandardNonGlobal, msg)
169+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
170+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)
171+
172+
def check_manufacturer(id):
173+
id_type = attribute_id_type(id)
174+
msg = f"Incorrect attribute range assessment, expecting manufacturer {id:08x}, type = {id_type}"
175+
asserts.assert_equal(id_type, AttributeIdType.kManufacturer, msg)
176+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
177+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)
178+
179+
def check_test(id):
180+
id_type = attribute_id_type(id)
181+
msg = f"Incorrect attribute range assessment, expecting test {id:08x}, type = {id_type}"
182+
asserts.assert_equal(id_type, AttributeIdType.kTest, msg)
183+
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
184+
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=False), msg)
185+
186+
def check_all_bad(id):
187+
id_type = attribute_id_type(id)
188+
msg = f"Incorrect attribute range assessment, expecting invalid {id:08x}, type = {id_type}"
189+
asserts.assert_equal(id_type, AttributeIdType.kInvalid, msg)
190+
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=True), msg)
191+
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=False), msg)
192+
193+
for id in standard_global_good:
194+
check_standard_global(id)
195+
for id in standard_global_bad:
196+
check_all_bad(id)
197+
for id in standard_non_global_good:
198+
check_standard_non_global(id)
199+
for id in standard_non_global_bad:
200+
check_all_bad(id)
201+
for id in manufacturer_good:
202+
check_manufacturer(id)
203+
for id in manufacturer_bad:
204+
check_all_bad(id)
205+
for id in test_good:
206+
check_test(id)
207+
for id in test_bad:
208+
check_all_bad(id)
209+
for id in prefix_bad:
210+
check_all_bad(id)
211+
212+
213+
if __name__ == "__main__":
214+
default_matter_test_main()

src/python_testing/global_attribute_ids.py

+108-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
# This file should be removed once we have a good way to get this from the codegen or XML
1919

20-
from enum import IntEnum
20+
from enum import Enum, IntEnum, auto
2121

2222

2323
class GlobalAttributeIds(IntEnum):
@@ -38,3 +38,110 @@ def to_name(self) -> str:
3838
return "FeatureMap"
3939
if self == GlobalAttributeIds.CLUSTER_REVISION_ID:
4040
return "ClusterRevision"
41+
42+
43+
class DeviceTypeIdType(Enum):
44+
kInvalid = auto(),
45+
kStandard = auto(),
46+
kManufacturer = auto(),
47+
kTest = auto(),
48+
49+
50+
class ClusterIdType(Enum):
51+
kInvalid = auto()
52+
kStandard = auto(),
53+
kManufacturer = auto(),
54+
kTest = auto(),
55+
56+
57+
class AttributeIdType(Enum):
58+
kInvalid = auto()
59+
kStandardGlobal = auto(),
60+
kStandardNonGlobal = auto(),
61+
kManufacturer = auto(),
62+
kTest = auto(),
63+
64+
# ID helper classes - this allows us to use the values from the prefix and suffix table directly
65+
# because the class handles the non-inclusive range.
66+
67+
68+
class IdRange():
69+
def __init__(self, min, max):
70+
self.min_max = range(min, max+1)
71+
72+
def __contains__(self, key):
73+
return key in self.min_max
74+
75+
76+
class PrefixIdRange(IdRange):
77+
def __contains__(self, id: int):
78+
return super().__contains__(id >> 16)
79+
80+
81+
class SuffixIdRange(IdRange):
82+
def __contains__(self, id: int):
83+
return super().__contains__(id & 0xFFFF)
84+
85+
86+
STANDARD_PREFIX = PrefixIdRange(0x0000, 0x0000)
87+
MANUFACTURER_PREFIX = PrefixIdRange(0x0001, 0xFFF0)
88+
TEST_PREFIX = PrefixIdRange(0xFFF1, 0xFFF4)
89+
90+
DEVICE_TYPE_ID_RANGE_SUFFIX = SuffixIdRange(0x0000, 0xBFFF)
91+
CLUSTER_ID_STANDARD_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x7FFF)
92+
CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX = SuffixIdRange(0xFC00, 0xFFFE)
93+
ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0xF000, 0xFFFE)
94+
ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x4FFF)
95+
96+
97+
def device_type_id_type(id: int) -> DeviceTypeIdType:
98+
if id in STANDARD_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
99+
return DeviceTypeIdType.kStandard
100+
if id in MANUFACTURER_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
101+
return DeviceTypeIdType.kManufacturer
102+
if id in TEST_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
103+
return DeviceTypeIdType.kTest
104+
return DeviceTypeIdType.kInvalid
105+
106+
107+
def is_valid_device_type_id(id_type: DeviceTypeIdType, allow_test=False) -> bool:
108+
valid = [DeviceTypeIdType.kStandard, DeviceTypeIdType.kManufacturer]
109+
if allow_test:
110+
valid.append(DeviceTypeIdType.kTest)
111+
return id_type in valid
112+
113+
114+
def cluster_id_type(id: int) -> ClusterIdType:
115+
if id in STANDARD_PREFIX and id in CLUSTER_ID_STANDARD_RANGE_SUFFIX:
116+
return ClusterIdType.kStandard
117+
if id in MANUFACTURER_PREFIX and id in CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX:
118+
return ClusterIdType.kManufacturer
119+
if id in TEST_PREFIX and id in CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX:
120+
return ClusterIdType.kTest
121+
return ClusterIdType.kInvalid
122+
123+
124+
def is_valid_cluster_id(id_type: ClusterIdType, allow_test: bool = False) -> bool:
125+
valid = [ClusterIdType.kStandard, ClusterIdType.kManufacturer]
126+
if allow_test:
127+
valid.append(ClusterIdType.kTest)
128+
return id_type in valid
129+
130+
131+
def attribute_id_type(id: int) -> AttributeIdType:
132+
if id in STANDARD_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
133+
return AttributeIdType.kStandardNonGlobal
134+
if id in STANDARD_PREFIX and id in ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX:
135+
return AttributeIdType.kStandardGlobal
136+
if id in MANUFACTURER_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
137+
return AttributeIdType.kManufacturer
138+
if id in TEST_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
139+
return AttributeIdType.kTest
140+
return AttributeIdType.kInvalid
141+
142+
143+
def is_valid_attribute_id(id_type: AttributeIdType, allow_test: bool = False):
144+
valid = [AttributeIdType.kStandardGlobal, AttributeIdType.kStandardNonGlobal, AttributeIdType.kManufacturer]
145+
if allow_test:
146+
valid.append(AttributeIdType.kTest)
147+
return id_type in valid

0 commit comments

Comments
 (0)