16
16
#
17
17
18
18
import xml .etree .ElementTree as ElementTree
19
+ from typing import Callable
19
20
20
- from conformance_support import ConformanceDecision , ConformanceException , ConformanceParseParameters , parse_callable_from_xml
21
- from matter_testing_support import MatterBaseTest , async_test_body , default_matter_test_main
21
+ from conformance_support import (ConformanceDecision , ConformanceException , ConformanceParseParameters , deprecated , disallowed ,
22
+ mandatory , optional , parse_basic_callable_from_xml , parse_callable_from_xml ,
23
+ parse_device_type_callable_from_xml , provisional , zigbee )
24
+ from matter_testing_support import MatterBaseTest , default_matter_test_main
22
25
from mobly import asserts
23
26
24
27
28
+ def basic_test (xml : str , cls : Callable ) -> None :
29
+ et = ElementTree .fromstring (xml )
30
+ xml_callable = parse_basic_callable_from_xml (et )
31
+ asserts .assert_true (isinstance (xml_callable , cls ), "Unexpected class parsed from basic conformance" )
32
+
33
+
25
34
class TestConformanceSupport (MatterBaseTest ):
26
- @async_test_body
27
- async def setup_class (self ):
35
+ def setup_class (self ):
28
36
super ().setup_class ()
29
37
# a small feature map
30
38
self .feature_names_to_bits = {'AB' : 0x01 , 'CD' : 0x02 }
@@ -46,26 +54,23 @@ async def setup_class(self):
46
54
self .params = ConformanceParseParameters (
47
55
feature_map = self .feature_names_to_bits , attribute_map = self .attribute_names_to_values , command_map = self .command_names_to_values )
48
56
49
- @async_test_body
50
- async def test_conformance_mandatory (self ):
57
+ def test_conformance_mandatory (self ):
51
58
xml = '<mandatoryConform />'
52
59
et = ElementTree .fromstring (xml )
53
60
xml_callable = parse_callable_from_xml (et , self .params )
54
61
for f in self .feature_maps :
55
62
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .MANDATORY )
56
63
asserts .assert_equal (str (xml_callable ), 'M' )
57
64
58
- @async_test_body
59
- async def test_conformance_optional (self ):
65
+ def test_conformance_optional (self ):
60
66
xml = '<optionalConform />'
61
67
et = ElementTree .fromstring (xml )
62
68
xml_callable = parse_callable_from_xml (et , self .params )
63
69
for f in self .feature_maps :
64
70
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .OPTIONAL )
65
71
asserts .assert_equal (str (xml_callable ), 'O' )
66
72
67
- @async_test_body
68
- async def test_conformance_disallowed (self ):
73
+ def test_conformance_disallowed (self ):
69
74
xml = '<disallowConform />'
70
75
et = ElementTree .fromstring (xml )
71
76
xml_callable = parse_callable_from_xml (et , self .params )
@@ -80,26 +85,23 @@ async def test_conformance_disallowed(self):
80
85
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .DISALLOWED )
81
86
asserts .assert_equal (str (xml_callable ), 'D' )
82
87
83
- @async_test_body
84
- async def test_conformance_provisional (self ):
88
+ def test_conformance_provisional (self ):
85
89
xml = '<provisionalConform />'
86
90
et = ElementTree .fromstring (xml )
87
91
xml_callable = parse_callable_from_xml (et , self .params )
88
92
for f in self .feature_maps :
89
93
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .PROVISIONAL )
90
94
asserts .assert_equal (str (xml_callable ), 'P' )
91
95
92
- @async_test_body
93
- async def test_conformance_zigbee (self ):
96
+ def test_conformance_zigbee (self ):
94
97
xml = '<condition name="Zigbee"/>'
95
98
et = ElementTree .fromstring (xml )
96
99
xml_callable = parse_callable_from_xml (et , self .params )
97
100
for f in self .feature_maps :
98
101
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .NOT_APPLICABLE )
99
102
asserts .assert_equal (str (xml_callable ), 'Zigbee' )
100
103
101
- @async_test_body
102
- async def test_conformance_mandatory_on_condition (self ):
104
+ def test_conformance_mandatory_on_condition (self ):
103
105
xml = ('<mandatoryConform>'
104
106
'<feature name="AB" />'
105
107
'</mandatoryConform>' )
@@ -151,8 +153,7 @@ async def test_conformance_mandatory_on_condition(self):
151
153
152
154
# test command in optional and in boolean - this is the same as attribute essentially, so testing every permutation is overkill
153
155
154
- @async_test_body
155
- async def test_conformance_optional_on_condition (self ):
156
+ def test_conformance_optional_on_condition (self ):
156
157
# single feature optional
157
158
xml = ('<optionalConform>'
158
159
'<feature name="AB" />'
@@ -228,8 +229,7 @@ async def test_conformance_optional_on_condition(self):
228
229
asserts .assert_equal (xml_callable (0x00 , [], c ), ConformanceDecision .NOT_APPLICABLE )
229
230
asserts .assert_equal (str (xml_callable ), '[cmd2]' )
230
231
231
- @async_test_body
232
- async def test_conformance_not_term_mandatory (self ):
232
+ def test_conformance_not_term_mandatory (self ):
233
233
# single feature not mandatory
234
234
xml = ('<mandatoryConform>'
235
235
'<notTerm>'
@@ -288,8 +288,7 @@ async def test_conformance_not_term_mandatory(self):
288
288
asserts .assert_equal (xml_callable (0x00 , a , []), ConformanceDecision .NOT_APPLICABLE )
289
289
asserts .assert_equal (str (xml_callable ), '!attr2' )
290
290
291
- @async_test_body
292
- async def test_conformance_not_term_optional (self ):
291
+ def test_conformance_not_term_optional (self ):
293
292
# single feature not optional
294
293
xml = ('<optionalConform>'
295
294
'<notTerm>'
@@ -319,8 +318,7 @@ async def test_conformance_not_term_optional(self):
319
318
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .NOT_APPLICABLE )
320
319
asserts .assert_equal (str (xml_callable ), '[!CD]' )
321
320
322
- @async_test_body
323
- async def test_conformance_and_term (self ):
321
+ def test_conformance_and_term (self ):
324
322
# and term for features only
325
323
xml = ('<mandatoryConform>'
326
324
'<andTerm>'
@@ -370,8 +368,7 @@ async def test_conformance_and_term(self):
370
368
asserts .assert_equal (xml_callable (f , a , []), ConformanceDecision .NOT_APPLICABLE )
371
369
asserts .assert_equal (str (xml_callable ), 'AB & attr2' )
372
370
373
- @async_test_body
374
- async def test_conformance_or_term (self ):
371
+ def test_conformance_or_term (self ):
375
372
# or term feature only
376
373
xml = ('<mandatoryConform>'
377
374
'<orTerm>'
@@ -421,8 +418,7 @@ async def test_conformance_or_term(self):
421
418
asserts .assert_equal (xml_callable (f , a , []), ConformanceDecision .NOT_APPLICABLE )
422
419
asserts .assert_equal (str (xml_callable ), 'AB | attr2' )
423
420
424
- @async_test_body
425
- async def test_conformance_and_term_with_not (self ):
421
+ def test_conformance_and_term_with_not (self ):
426
422
# and term with not
427
423
xml = ('<optionalConform>'
428
424
'<andTerm>'
@@ -441,8 +437,7 @@ async def test_conformance_and_term_with_not(self):
441
437
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .NOT_APPLICABLE )
442
438
asserts .assert_equal (str (xml_callable ), '[!AB & CD]' )
443
439
444
- @async_test_body
445
- async def test_conformance_or_term_with_not (self ):
440
+ def test_conformance_or_term_with_not (self ):
446
441
# or term with not on second feature
447
442
xml = ('<mandatoryConform>'
448
443
'<orTerm>'
@@ -479,8 +474,7 @@ async def test_conformance_or_term_with_not(self):
479
474
asserts .assert_equal (xml_callable (f , [], []), ConformanceDecision .NOT_APPLICABLE )
480
475
asserts .assert_equal (str (xml_callable ), '[!(AB | CD)]' )
481
476
482
- @async_test_body
483
- async def test_conformance_and_term_with_three_terms (self ):
477
+ def test_conformance_and_term_with_three_terms (self ):
484
478
# and term with three features
485
479
xml = ('<optionalConform>'
486
480
'<andTerm>'
@@ -519,8 +513,7 @@ async def test_conformance_and_term_with_three_terms(self):
519
513
asserts .assert_equal (xml_callable (f , a , c ), ConformanceDecision .NOT_APPLICABLE )
520
514
asserts .assert_equal (str (xml_callable ), '[AB & attr1 & cmd1]' )
521
515
522
- @async_test_body
523
- async def test_conformance_or_term_with_three_terms (self ):
516
+ def test_conformance_or_term_with_three_terms (self ):
524
517
# or term with three features
525
518
xml = ('<optionalConform>'
526
519
'<orTerm>'
@@ -671,6 +664,92 @@ def test_conformance_greater(self):
671
664
except ConformanceException :
672
665
pass
673
666
667
+ def test_basic_conformance (self ):
668
+ basic_test ('<mandatoryConform />' , mandatory )
669
+ basic_test ('<optionalConform />' , optional )
670
+ basic_test ('<disallowConform />' , disallowed )
671
+ basic_test ('<deprecateConform />' , deprecated )
672
+ basic_test ('<provisionalConform />' , provisional )
673
+ basic_test ('<condition name="zigbee" />' , zigbee )
674
+
675
+ # feature is not basic so we should get an exception
676
+ xml = '<feature name="CD" />'
677
+ et = ElementTree .fromstring (xml )
678
+ try :
679
+ parse_basic_callable_from_xml (et )
680
+ asserts .fail ("Unexpected success parsing non-basic conformance" )
681
+ except ConformanceException :
682
+ pass
683
+
684
+ # mandatory tag is basic, but this one is a wrapper, so we should get a TypeError
685
+ xml = ('<mandatoryConform>'
686
+ '<andTerm>'
687
+ '<feature name="AB" />'
688
+ '<notTerm>'
689
+ '<feature name="CD" />'
690
+ '</notTerm>'
691
+ '</andTerm>'
692
+ '</mandatoryConform>' )
693
+ et = ElementTree .fromstring (xml )
694
+ try :
695
+ parse_basic_callable_from_xml (et )
696
+ asserts .fail ("Unexpected success parsing mandatory wrapper" )
697
+ except ConformanceException :
698
+ pass
699
+
700
+ def test_device_type_conformance (self ):
701
+ msg = "Unexpected conformance returned for device type"
702
+ xml = ('<mandatoryConform>'
703
+ '<condition name="zigbee" />'
704
+ '</mandatoryConform>' )
705
+ et = ElementTree .fromstring (xml )
706
+ xml_callable = parse_device_type_callable_from_xml (et )
707
+ asserts .assert_equal (str (xml_callable ), 'Zigbee' , msg )
708
+ asserts .assert_equal (xml_callable (0 , [], []), ConformanceDecision .NOT_APPLICABLE , msg )
709
+
710
+ xml = ('<optionalConform>'
711
+ '<condition name="zigbee" />'
712
+ '</optionalConform>' )
713
+ et = ElementTree .fromstring (xml )
714
+ xml_callable = parse_device_type_callable_from_xml (et )
715
+ # expect no exception here
716
+ asserts .assert_equal (str (xml_callable ), '[Zigbee]' , msg )
717
+ asserts .assert_equal (xml_callable (0 , [], []), ConformanceDecision .NOT_APPLICABLE , msg )
718
+
719
+ # otherwise conforms are allowed
720
+ xml = ('<otherwiseConform>'
721
+ '<condition name="zigbee" />'
722
+ '<provisionalConform />'
723
+ '</otherwiseConform>' )
724
+ et = ElementTree .fromstring (xml )
725
+ xml_callable = parse_device_type_callable_from_xml (et )
726
+ # expect no exception here
727
+ asserts .assert_equal (str (xml_callable ), 'Zigbee, P' , msg )
728
+ asserts .assert_equal (xml_callable (0 , [], []), ConformanceDecision .PROVISIONAL , msg )
729
+
730
+ # Device type conditions or features don't correspond to anything in the spec, so the XML takes a best
731
+ # guess as to what they are. We should be able to parse features, conditions, attributes as the same
732
+ # thing.
733
+ # TODO: allow querying conformance for conditional device features
734
+ # TODO: adjust conformance call function to accept a list of features and evaluate based on that
735
+ xml = ('<mandatoryConform>'
736
+ '<feature name="CD" />'
737
+ '</mandatoryConform>' )
738
+ et = ElementTree .fromstring (xml )
739
+ xml_callable = parse_device_type_callable_from_xml (et )
740
+ asserts .assert_equal (str (xml_callable ), 'CD' , msg )
741
+ # Device features are always optional (at least for now), even though we didn't pass this feature in
742
+ asserts .assert_equal (xml_callable (0 , [], []), ConformanceDecision .OPTIONAL )
743
+
744
+ xml = ('<otherwiseConform>'
745
+ '<feature name="CD" />'
746
+ '<condition name="testy" />'
747
+ '</otherwiseConform>' )
748
+ et = ElementTree .fromstring (xml )
749
+ xml_callable = parse_device_type_callable_from_xml (et )
750
+ asserts .assert_equal (str (xml_callable ), 'CD, testy' , msg )
751
+ asserts .assert_equal (xml_callable (0 , [], []), ConformanceDecision .OPTIONAL )
752
+
674
753
675
754
if __name__ == "__main__" :
676
755
default_matter_test_main ()
0 commit comments