From b2b62752a610d9ab0998665746d26580fc818ed2 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Thu, 23 Jan 2025 11:43:14 -0800 Subject: [PATCH] Consolidate basic assert tests (#37168) --- src/python_testing/TC_DGSW_2_1.py | 17 +-- src/python_testing/TC_DGSW_2_2.py | 17 +-- src/python_testing/TC_DGSW_2_3.py | 27 ++-- src/python_testing/TC_DGWIFI_2_1.py | 23 +-- .../chip/testing/matter_asserts.py | 131 ++++++++++++++---- .../chip/testing/matter_testing.py | 40 ------ .../chip/testing/test_matter_asserts.py | 125 +++++++++++++++++ 7 files changed, 271 insertions(+), 109 deletions(-) diff --git a/src/python_testing/TC_DGSW_2_1.py b/src/python_testing/TC_DGSW_2_1.py index 17ccef1b047436..86022bef0fd193 100644 --- a/src/python_testing/TC_DGSW_2_1.py +++ b/src/python_testing/TC_DGSW_2_1.py @@ -36,6 +36,7 @@ # import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main @@ -81,41 +82,41 @@ async def test_TC_DGSW_2_1(self): # Validate each element in the thread_metrics_list for metric in thread_metrics_list: # The Id field is mandatory - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") # Validate the optional Name field if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") # Validate the optional StackFreeCurrent field if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") # Validate the optional StackFreeMinimum field if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") # Validate the optional StackSize field if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # STEP 3: TH reads from the DUT the CurrentHeapFree attribute self.step(3) if self.pics_guard(attributes.CurrentHeapFree.attribute_id in attribute_list): current_heap_free_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapFree) - self.assert_valid_uint64(current_heap_free_attr, "CurrentHeapFree") + matter_asserts.assert_valid_uint64(current_heap_free_attr, "CurrentHeapFree") # STEP 4: TH reads from the DUT the CurrentHeapUsed attribute self.step(4) if self.pics_guard(attributes.CurrentHeapUsed.attribute_id in attribute_list): current_heap_used_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapUsed) - self.assert_valid_uint64(current_heap_used_attr, "CurrentHeapUsed") + matter_asserts.assert_valid_uint64(current_heap_used_attr, "CurrentHeapUsed") # STEP 5: TH reads from the DUT the CurrentHeapHighWatermark attribute self.step(5) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): current_heap_high_watermark_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(current_heap_high_watermark_attr, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(current_heap_high_watermark_attr, "CurrentHeapHighWatermark") if __name__ == "__main__": diff --git a/src/python_testing/TC_DGSW_2_2.py b/src/python_testing/TC_DGSW_2_2.py index 03d4b0abc72443..1d93c9da8ab942 100644 --- a/src/python_testing/TC_DGSW_2_2.py +++ b/src/python_testing/TC_DGSW_2_2.py @@ -42,8 +42,8 @@ # import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main -from mobly import asserts class TC_DGSW_2_2(MatterBaseTest): @@ -66,22 +66,13 @@ def validate_soft_fault_event_data(self, event_data): """ # Validate 'Id' field: Ensure it is a uint64 type - asserts.assert_true( - self.is_valid_uint_value(event_data.id, bit_count=64), - "The 'Id' field must be a uint64 type" - ) + matter_asserts.assert_valid_uint64(event_data.id, "Id") # Validate 'Name' field: Ensure it is a string - asserts.assert_true( - isinstance(event_data.name, str), - "The 'Name' field must be a string type" - ) + matter_asserts.assert_is_string(event_data.name, "Name") # Validate 'FaultRecording' field: Ensure it is an octet string (bytes or bytearray) - asserts.assert_true( - self.is_valid_octet_string(event_data.faultRecording), - "The 'FaultRecording' field must be an octet string (bytes or bytearray)" - ) + matter_asserts.assert_is_octstr(event_data.faultRecording, "FaultRecording") def desc_TC_DGSW_2_2(self) -> str: """Returns a description of this test""" diff --git a/src/python_testing/TC_DGSW_2_3.py b/src/python_testing/TC_DGSW_2_3.py index f713a563a54b6c..1daec5e2db6b24 100644 --- a/src/python_testing/TC_DGSW_2_3.py +++ b/src/python_testing/TC_DGSW_2_3.py @@ -38,6 +38,7 @@ import logging import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -94,31 +95,31 @@ async def test_TC_DGSW_2_3(self): # Iterate over all items in the list and validate each one for metric in thread_metrics_original: # The Id field is mandatory - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # STEP 4: TH reads from the DUT the CurrentHeapHighWatermark attribute self.step(4) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): high_watermark_original = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(high_watermark_original, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(high_watermark_original, "CurrentHeapHighWatermark") # STEP 5: TH reads from the DUT the CurrentHeapUsed attribute self.step(5) if self.pics_guard(attributes.CurrentHeapUsed.attribute_id in attribute_list): current_heap_used_original = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapUsed) - self.assert_valid_uint64(current_heap_used_original, "CurrentHeapUsed") + matter_asserts.assert_valid_uint64(current_heap_used_original, "CurrentHeapUsed") if high_watermark_original is not None: asserts.assert_true(current_heap_used_original <= high_watermark_original, @@ -133,7 +134,7 @@ async def test_TC_DGSW_2_3(self): self.step(7) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): current_heap_high_watermark = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(current_heap_high_watermark, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(current_heap_high_watermark, "CurrentHeapHighWatermark") # Verify that the returned value is <= high_watermark_original asserts.assert_true(current_heap_high_watermark <= high_watermark_original, @@ -152,19 +153,19 @@ async def test_TC_DGSW_2_3(self): # Validate all elements in the list for metric in thread_metrics_reset: - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # Ensure the list length matches thread_metrics_original to simplify matching asserts.assert_equal(len(thread_metrics_reset), len(thread_metrics_original), diff --git a/src/python_testing/TC_DGWIFI_2_1.py b/src/python_testing/TC_DGWIFI_2_1.py index 707deb0198047f..2320385da0a763 100644 --- a/src/python_testing/TC_DGWIFI_2_1.py +++ b/src/python_testing/TC_DGWIFI_2_1.py @@ -34,6 +34,7 @@ import chip.clusters as Clusters from chip.clusters.Types import Nullable, NullValue +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -131,7 +132,7 @@ async def test_TC_DGWIFI_2_1(self): # Just do a minimal check here; you can refine or extend based on the spec. if security_type is not NullValue: security_type_value = security_type.Value - self.assert_valid_uint8(security_type_value, "SecurityType") + matter_asserts.assert_valid_uint8(security_type_value, "SecurityType") # Check if the security_type is a valid SecurityTypeEnum member self.assert_true( @@ -154,7 +155,7 @@ async def test_TC_DGWIFI_2_1(self): # WiFiVersion is an enum. If not configured or operational, might be NULL. if wifi_version is not NullValue: wifi_version_value = wifi_version.Value - self.assert_valid_uint8(wifi_version_value, "WiFiVersion") + matter_asserts.assert_valid_uint8(wifi_version_value, "WiFiVersion") # Check if the wifi_version is a valid WiFiVersionEnum member self.assert_true(wifi_version_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum], @@ -171,7 +172,7 @@ async def test_TC_DGWIFI_2_1(self): channel_number = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.ChannelNumber) # If not operational, might be NULL. Else we expect an unsigned integer channel. if channel_number is not NullValue: - self.assert_valid_uint16(channel_number.Value, "ChannelNumber") + matter_asserts.assert_valid_uint16(channel_number.Value, "ChannelNumber") # # STEP 6: TH reads RSSI attribute @@ -195,7 +196,7 @@ async def test_TC_DGWIFI_2_1(self): "BeaconLostCount must be of type 'Nullable' when not None.") if beacon_lost_count is not NullValue: - self.assert_valid_uint32(beacon_lost_count.Value, "BeaconLostCount") + matter_asserts.assert_valid_uint32(beacon_lost_count.Value, "BeaconLostCount") # # STEP 8: TH reads BeaconRxCount attribute @@ -207,7 +208,7 @@ async def test_TC_DGWIFI_2_1(self): "BeaconRxCount must be of type 'Nullable' when not None.") if beacon_rx_count is not NullValue: - self.assert_valid_uint32(beacon_rx_count.Value, "BeaconRxCount") + matter_asserts.assert_valid_uint32(beacon_rx_count.Value, "BeaconRxCount") # # STEP 9: TH reads PacketMulticastRxCount attribute @@ -219,7 +220,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketMulticastRxCount must be of type 'Nullable' when not None.") if pkt_multi_rx is not NullValue: - self.assert_valid_uint32(pkt_multi_rx.Value, "PacketMulticastRxCount") + matter_asserts.assert_valid_uint32(pkt_multi_rx.Value, "PacketMulticastRxCount") # # STEP 10: TH reads PacketMulticastTxCount attribute @@ -231,7 +232,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketMulticastTxCount must be of type 'Nullable' when not None.") if pkt_multi_tx is not NullValue: - self.assert_valid_uint32(pkt_multi_tx.Value, "PacketMulticastTxCount") + matter_asserts.assert_valid_uint32(pkt_multi_tx.Value, "PacketMulticastTxCount") # # STEP 11: TH reads PacketUnicastRxCount attribute @@ -243,7 +244,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketUnicastRxCount must be of type 'Nullable' when not None.") if pkt_uni_rx is not NullValue: - self.assert_valid_uint32(pkt_uni_rx.Value, "PacketUnicastRxCount") + matter_asserts.assert_valid_uint32(pkt_uni_rx.Value, "PacketUnicastRxCount") # # STEP 12: TH reads PacketUnicastTxCount attribute @@ -255,7 +256,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketUnicastTxCount must be of type 'Nullable' when not None.") if pkt_uni_tx is not NullValue: - self.assert_valid_uint32(pkt_uni_tx.Value, "PacketUnicastTxCount") + matter_asserts.assert_valid_uint32(pkt_uni_tx.Value, "PacketUnicastTxCount") # # STEP 13: TH reads CurrentMaxRate attribute @@ -268,7 +269,7 @@ async def test_TC_DGWIFI_2_1(self): "CurrentMaxRate must be of type 'Nullable' when not None.") if current_max_rate is not NullValue: - self.assert_valid_uint64(current_max_rate.Value, "CurrentMaxRate") + matter_asserts.assert_valid_uint64(current_max_rate.Value, "CurrentMaxRate") # # STEP 14: TH reads OverrunCount attribute @@ -281,7 +282,7 @@ async def test_TC_DGWIFI_2_1(self): "OverrunCount must be of type 'Nullable' when not None.") if overrun_count is not NullValue: - self.assert_valid_uint64(overrun_count.Value, "OverrunCount") + matter_asserts.assert_valid_uint64(overrun_count.Value, "OverrunCount") if __name__ == "__main__": diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py index b7d6fca4a9eccd..4b17612d7e24cf 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py @@ -8,39 +8,102 @@ T = TypeVar('T') + +# Internal helper functions + +def is_valid_uint_value(value: Any, bit_count: int = 64) -> bool: + """ + Checks if 'value' is a non-negative integer that fits into 'bit_count' bits. + For example, bit_count=32 => 0 <= value <= 0xFFFFFFFF + """ + if not isinstance(value, int): + return False + if value < 0: + return False + return value < (1 << bit_count) + + +def is_valid_int_value(value: Any, bit_count: int = 8) -> bool: + """ + Checks if 'value' is a signed integer that fits into 'bit_count' bits. + For example, for int8: -128 <= value <= 127. + """ + min_val = -(1 << (bit_count - 1)) + max_val = (1 << (bit_count - 1)) - 1 + return isinstance(value, int) and (min_val <= value <= max_val) + + +def is_valid_bool_value(value: Any) -> bool: + """ + Checks if 'value' is a boolean. + """ + return isinstance(value, bool) + + # Integer assertions +def assert_valid_uint64(value: Any, description: str) -> None: + """ + Asserts that the value is a valid uint64 (0 <= value < 2^64). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=64), + f"{description} must be a valid uint64 integer") + def assert_valid_uint32(value: Any, description: str) -> None: """ - Asserts that the value is a valid uint32. + Asserts that the value is a valid uint32 (0 <= value < 2^32). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=32), + f"{description} must be a valid uint32 integer") - Args: - value: The value to check - description: User-defined description for error messages - Raises: - AssertionError: If value is not an integer or outside the uint32 range (0 to 0xFFFFFFFF) +def assert_valid_uint16(value: Any, description: str) -> None: """ - asserts.assert_true(isinstance(value, int), f"{description} must be an integer") - asserts.assert_greater_equal(value, 0, f"{description} must be non-negative") - asserts.assert_less_equal(value, 0xFFFFFFFF, f"{description} must not exceed 0xFFFFFFFF") + Asserts that the value is a valid uint16 (0 <= value < 2^16). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=16), + f"{description} must be a valid uint16 integer") -def assert_valid_uint64(value: Any, description: str) -> None: +def assert_valid_uint8(value: Any, description: str) -> None: """ - Asserts that the value is a valid uint64. + Asserts that the value is a valid uint8 (0 <= value < 2^8). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=8), + f"{description} must be a valid uint8 integer") - Args: - value: The value to check - description: User-defined description for error messages - Raises: - AssertionError: If value is not an integer or outside the uint64 range (0 to 0xFFFFFFFFFFFFFFFF) +def assert_valid_int64(value: Any, description: str) -> None: """ - asserts.assert_true(isinstance(value, int), f"{description} must be an integer") - asserts.assert_greater_equal(value, 0, f"{description} must be non-negative") - asserts.assert_less_equal(value, 0xFFFFFFFFFFFFFFFF, f"{description} must not exceed 0xFFFFFFFFFFFFFFFF") + Asserts that the value is a valid int64 (-2^63 <= value <= 2^63-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=64), + f"{description} must be a valid int64 integer") + + +def assert_valid_int32(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int32 (-2^31 <= value <= 2^31-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=32), + f"{description} must be a valid int32 integer") + + +def assert_valid_int16(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int16 (-2^15 <= value <= 2^15-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=16), + f"{description} must be a valid int16 integer") + + +def assert_valid_int8(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int8 (-128 <= value <= 127). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=8), + f"{description} must be a valid int8 integer") def assert_int_in_range(value: Any, min_value: int, max_value: int, description: str) -> None: @@ -60,8 +123,8 @@ def assert_int_in_range(value: Any, min_value: int, max_value: int, description: asserts.assert_greater_equal(value, min_value, f"{description} must be greater than or equal to {min_value}") asserts.assert_less_equal(value, max_value, f"{description} must be less than or equal to {max_value}") -# List assertions +# List assertions def assert_list(value: Any, description: str, min_length: Optional[int] = None, max_length: Optional[int] = None) -> None: """ @@ -104,8 +167,8 @@ def assert_list_element_type(value: List[Any], description: str, expected_type: asserts.assert_true(isinstance(item, expected_type), f"{description}[{i}] must be of type {expected_type.__name__}") -# String assertions +# String assertions def assert_is_string(value: Any, description: str) -> None: """ @@ -139,11 +202,9 @@ def assert_string_length(value: Any, description: str, min_length: Optional[int] - Use min_length=None, max_length=None to only validate string type (same as assert_is_string) """ assert_is_string(value, description) - if min_length is not None: asserts.assert_greater_equal(len(value), min_length, f"{description} length must be at least {min_length} characters") - if max_length is not None: asserts.assert_less_equal(len(value), max_length, f"{description} length must not exceed {max_length} characters") @@ -162,8 +223,22 @@ def assert_non_empty_string(value: Any, description: str) -> None: """ assert_string_length(value, description, min_length=1) -# Matter-specific assertions +def assert_is_octstr(value: Any, description: str) -> None: + """ + Asserts that the value is a octet string. + + Args: + value: The value to check + description: User-defined description for error messages + + Raises: + AssertionError: If value is not a octet string (bytes) + """ + asserts.assert_true(isinstance(value, bytes), f"{description} must be a octet string (bytes)") + + +# Matter-specific assertions def assert_string_matches_pattern(value: str, description: str, pattern: str) -> None: """ @@ -243,3 +318,11 @@ def assert_standard_command_id(id: int) -> None: from chip.testing.global_attribute_ids import is_standard_command_id asserts.assert_true(is_standard_command_id(id), f"Not a standard command ID: {hex(id)}") + + +def assert_valid_enum(value: Any, description: str, enum_type: type) -> None: + """ + Asserts that 'value' is a valid instance of the specified enum type. + """ + asserts.assert_true(isinstance(value, enum_type), + f"{description} must be of type {enum_type.__name__}") diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 799b950882142a..1054463ea64489 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -972,46 +972,6 @@ def __init__(self, *args): # The named pipe name must be set in the derived classes self.app_pipe = None - @staticmethod - def is_valid_uint_value(value, bit_count=64): - """ - Checks if 'value' is a non-negative integer fitting into 'bit_count' bits. - For example, bit_count=32 => must fit within 0 <= value <= 0xFFFFFFFF - """ - if not isinstance(value, int): - return False - if value < 0: - return False - return value < 2**bit_count - - @staticmethod - def is_valid_str_value(value): - return isinstance(value, str) and len(value) > 0 - - def assert_valid_uint64(self, value, field_name): - """Asserts that the value is a valid uint64.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=64), - f"{field_name} should be a uint64 or NULL.") - - def assert_valid_uint32(self, value, field_name): - """Asserts that the value is a valid uint32.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=32), - f"{field_name} should be a uint32 or NULL.") - - def assert_valid_uint16(self, value, field_name): - """Asserts that the value is a valid uint16.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=16), - f"{field_name} should be a uint16 or NULL.") - - def assert_valid_uint8(self, value, field_name): - """Asserts that the value is a valid uint16.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=8), - f"{field_name} should be a uint8 or NULL.") - - def assert_valid_str(self, value, field_name): - """Asserts that the value is a non-empty string.""" - asserts.assert_true(self.is_valid_str_value(value), f"{field_name} field should be a non-empty string") - def get_test_steps(self, test: str) -> list[TestStep]: ''' Retrieves the test step list for the given test diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py b/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py index 2b1c55d629f1f7..88df62ffdad721 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py @@ -1,11 +1,17 @@ """Unit tests for matter_asserts module.""" +import enum import unittest from chip.testing import matter_asserts from mobly import signals +class MyTestEnum(enum.Enum): + VALID_MEMBER = 1 + ANOTHER_MEMBER = 2 + + class TestMatterAsserts(unittest.TestCase): """Unit tests for matter_asserts module.""" @@ -42,6 +48,90 @@ def test_assert_valid_uint64(self): with self.assertRaises(signals.TestFailure): matter_asserts.assert_valid_uint64(42.0, "test_float") + def test_assert_valid_uint16(self): + """Test assert_valid_uint16 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_uint16(0, "test_min") + matter_asserts.assert_valid_uint16(0xFFFF, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16(-1, "test_negative") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16(0x10000, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16("42", "test_string") + + def test_assert_valid_uint8(self): + """Test assert_valid_uint8 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_uint8(0, "test_min") + matter_asserts.assert_valid_uint8(0xFF, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8(-1, "test_negative") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8(0x100, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8("42", "test_string") + + def test_assert_valid_int64(self): + """Test assert_valid_int64 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int64(-2**63, "test_min") + matter_asserts.assert_valid_int64(2**63 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64(-2**63 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64(2**63, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64("42", "test_string") + + def test_assert_valid_int32(self): + """Test assert_valid_int32 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int32(-2**31, "test_min") + matter_asserts.assert_valid_int32(2**31 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32(-2**31 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32(2**31, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32("42", "test_string") + + def test_assert_valid_int16(self): + """Test assert_valid_int16 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int16(-2**15, "test_min") + matter_asserts.assert_valid_int16(2**15 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16(-2**15 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16(2**15, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16("42", "test_string") + + def test_assert_valid_int8(self): + """Test assert_valid_int8 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int8(-128, "test_min") + matter_asserts.assert_valid_int8(127, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8(-129, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8(128, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8("42", "test_string") + def test_assert_int_in_range(self): """Test assert_int_in_range with valid and invalid values.""" # Valid cases @@ -126,6 +216,41 @@ def test_assert_non_empty_string(self): with self.assertRaises(signals.TestFailure): matter_asserts.assert_non_empty_string(42, "test_not_string") + def test_assert_is_octstr(self): + """Test assert_is_octstr with valid and invalid values.""" + # Valid case + matter_asserts.assert_is_octstr(b"", "test_empty_bytes") + matter_asserts.assert_is_octstr(b"\x01\x02", "test_some_bytes") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_is_octstr("not_bytes", "test_string") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_is_octstr(123, "test_int") + + def test_assert_string_matches_pattern(self): + """Test assert_string_matches_pattern with valid and invalid values.""" + # Valid cases + matter_asserts.assert_string_matches_pattern("abc123", "test_alphanumeric", r'^[a-z0-9]+$') + matter_asserts.assert_string_matches_pattern("hello", "test_hello", r'^hello$') + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_string_matches_pattern(123, "test_not_string", r'^.*$') + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_string_matches_pattern("abc!", "test_pattern_mismatch", r'^[a-z0-9]+$') + + def test_assert_valid_enum(self): + """Test assert_valid_enum with valid and invalid values.""" + # Valid case + matter_asserts.assert_valid_enum(MyTestEnum.VALID_MEMBER, "test_enum_member", MyTestEnum) + + # Invalid cases: not an enum member or wrong type + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_enum(1, "test_int_instead_of_enum", MyTestEnum) + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_enum("INVALID", "test_string", MyTestEnum) + # Matter-specific assertion tests def test_assert_valid_attribute_id(self): """Test assert_valid_attribute_id with valid and invalid values."""