diff --git a/src/python_testing/TestConformanceSupport.py b/src/python_testing/TestConformanceSupport.py
index b383f1acb63cc7..f71eb3ed1d531f 100644
--- a/src/python_testing/TestConformanceSupport.py
+++ b/src/python_testing/TestConformanceSupport.py
@@ -17,7 +17,7 @@
import xml.etree.ElementTree as ElementTree
-from conformance_support import ConformanceDecision, ConformanceParseParameters, parse_callable_from_xml
+from conformance_support import ConformanceDecision, ConformanceException, ConformanceParseParameters, parse_callable_from_xml
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from mobly import asserts
@@ -616,6 +616,61 @@ def test_conformance_otherwise(self):
asserts.assert_equal(xml_callable(f, [], []), ConformanceDecision.PROVISIONAL)
asserts.assert_equal(str(xml_callable), 'AB & !CD, P')
+ def test_conformance_greater(self):
+ # AB, [CD]
+ xml = (''
+ ''
+ ''
+ ''
+ ''
+ '')
+ et = ElementTree.fromstring(xml)
+ xml_callable = parse_callable_from_xml(et, self.params)
+ # TODO: switch this to check greater than once the update to the base is done (#33422)
+ asserts.assert_equal(xml_callable(0x00, [], []), ConformanceDecision.OPTIONAL)
+ asserts.assert_equal(str(xml_callable), 'attr1 > 1')
+
+ # Ensure that we can only have greater terms with exactly 2 value
+ xml = (''
+ ''
+ ''
+ ''
+ ''
+ ''
+ '')
+ et = ElementTree.fromstring(xml)
+ try:
+ xml_callable = parse_callable_from_xml(et, self.params)
+ asserts.fail("Incorrectly parsed bad greaterTerm XML with > 2 values")
+ except ConformanceException:
+ pass
+
+ xml = (''
+ ''
+ ''
+ ''
+ '')
+ et = ElementTree.fromstring(xml)
+ try:
+ xml_callable = parse_callable_from_xml(et, self.params)
+ asserts.fail("Incorrectly parsed bad greaterTerm XML with < 2 values")
+ except ConformanceException:
+ pass
+
+ # Only attributes and literals allowed because arithmetic operations require values
+ xml = (''
+ ''
+ ''
+ ''
+ ''
+ '')
+ et = ElementTree.fromstring(xml)
+ try:
+ xml_callable = parse_callable_from_xml(et, self.params)
+ asserts.fail("Incorrectly parsed greater term with feature value")
+ except ConformanceException:
+ pass
+
if __name__ == "__main__":
default_matter_test_main()
diff --git a/src/python_testing/conformance_support.py b/src/python_testing/conformance_support.py
index 89157c226351b1..025c1afa678995 100644
--- a/src/python_testing/conformance_support.py
+++ b/src/python_testing/conformance_support.py
@@ -33,10 +33,12 @@
AND_TERM = 'andTerm'
OR_TERM = 'orTerm'
NOT_TERM = 'notTerm'
+GREATER_TERM = 'greaterTerm'
FEATURE_TAG = 'feature'
ATTRIBUTE_TAG = 'attribute'
COMMAND_TAG = 'command'
CONDITION_TAG = 'condition'
+LITERAL_TAG = 'literal'
class ConformanceException(Exception):
@@ -123,6 +125,18 @@ def __str__(self):
return 'P'
+class literal:
+ def __init__(self, value: str):
+ self.value = int(value)
+
+ def __call__(self):
+ # This should never be called
+ raise ConformanceException('Literal conformance function should not be called - this is simply a value holder')
+
+ def __str__(self):
+ return str(self.value)
+
+
class feature:
def __init__(self, requiredFeature: uint, code: str):
self.requiredFeature = requiredFeature
@@ -267,8 +281,25 @@ def __str__(self):
op_strs = [str(op) for op in self.op_list]
return f'({" | ".join(op_strs)})'
-# TODO: add xor operation once it's required
-# TODO: how would equal and unequal operations work here?
+
+class greater_operation:
+ def _type_ok(self, op: Callable):
+ return type(op) == attribute or type(op) == literal
+
+ def __init__(self, op1: Callable, op2: Callable):
+ if not self._type_ok(op1) or not self._type_ok(op2):
+ raise ConformanceException('Arithmetic operations can only have attribute or literal value children')
+ self.op1 = op1
+ self.op2 = op2
+
+ def __call__(self, feature_map: uint, attribute_list: list[uint], all_command_list: list[uint]) -> ConformanceDecision:
+ # For now, this is fully optional, need to implement this properly later, but it requires access to the actual attribute values
+ # We need to reach into the attribute, but can't use it directly because the attribute callable is an EXISTENCE check and
+ # the arithmetic functions require a value.
+ return ConformanceDecision.OPTIONAL
+
+ def __str__(self):
+ return f'{str(self.op1)} > {str(self.op2)}'
class otherwise:
@@ -325,6 +356,8 @@ def parse_callable_from_xml(element: ElementTree.Element, params: ConformancePar
return command(params.command_map[element.get('name')], element.get('name'))
elif element.tag == CONDITION_TAG and element.get('name').lower() == 'zigbee':
return zigbee()
+ elif element.tag == LITERAL_TAG:
+ return literal(element.get('value'))
else:
raise ConformanceException(
f'Unexpected xml conformance element with no children {str(element.tag)} {str(element.attrib)}')
@@ -354,5 +387,9 @@ def parse_callable_from_xml(element: ElementTree.Element, params: ConformancePar
return not_operation(ops[0])
elif element.tag == OTHERWISE_CONFORM:
return otherwise(ops)
+ elif element.tag == GREATER_TERM:
+ if len(ops) != 2:
+ raise ConformanceException(f'Greater than term found with more than two subelements {list(element)}')
+ return greater_operation(ops[0], ops[1])
else:
raise ConformanceException(f'Unexpected conformance tag with children {element}')