forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_generators.py
executable file
·170 lines (131 loc) · 5.65 KB
/
test_generators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env python3
# Copyright (c) 2022 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import unittest
import yaml
import logging
from typing import List
from dataclasses import dataclass, field
try:
from idl.matter_idl_parser import CreateParser
except:
import sys
sys.path.append(os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))
from idl.matter_idl_parser import CreateParser
from idl.matter_idl_types import Idl
from idl.generators.java import JavaGenerator
from idl.generators.bridge import BridgeGenerator
from idl.generators import GeneratorStorage
TESTS_DIR = os.path.join(os.path.dirname(__file__), "tests")
REGENERATE_GOLDEN_IMAGES = False
@dataclass
class ExpectedOutput:
file_name: str
golden_path: str
@dataclass
class GeneratorTestCase:
input_idl: str
outputs: List[ExpectedOutput] = field(default_factory=list)
def add_outputs(self, yaml_outputs_dict):
for file_name, golden_path in yaml_outputs_dict.items():
self.outputs.append(ExpectedOutput(
file_name=file_name, golden_path=golden_path))
class TestCaseStorage(GeneratorStorage):
def __init__(self, test_case: GeneratorTestCase, checker: unittest.TestCase):
super().__init__()
self.test_case = test_case
self.checker = checker
self.checked_files = set()
def get_existing_data_path(self, relative_path: str):
for expected in self.test_case.outputs:
if expected.file_name == relative_path:
return os.path.join(TESTS_DIR, expected.golden_path)
self.checker.fail("Expected output %s not found" % relative_path)
return None
def get_existing_data(self, relative_path: str):
self.checked_files.add(relative_path)
path = self.get_existing_data_path(relative_path)
if path:
with open(path, 'rt') as golden:
return golden.read()
# This will attempt a new write, causing a unit test failure
self.checker.fail("Expected output %s not found" % relative_path)
return None
def write_new_data(self, relative_path: str, content: str):
if REGENERATE_GOLDEN_IMAGES:
# Expect writing only on regeneration
with open(self.get_existing_data_path(relative_path), 'wt') as golden:
golden.write(content)
return
# This is a unit test failure: we do NOT expect
# to write any new data
# This will display actual diffs in the output files
self.checker.assertEqual(
self.get_existing_data(relative_path), content)
# Even if no diff, to be build system friendly, we do NOT expect any
# actual data writes.
raise AssertionError("Unexpected write to %s" % relative_path)
@dataclass
class GeneratorTest:
generator_name: str
test_cases: List[GeneratorTestCase] = field(default_factory=list)
def add_test_cases(self, yaml_test_case_dict):
for idl_path, outputs in yaml_test_case_dict.items():
test_case = GeneratorTestCase(input_idl=idl_path)
test_case.add_outputs(outputs)
self.test_cases.append(test_case)
def _create_generator(self, storage: GeneratorStorage, idl: Idl):
if self.generator_name.lower() == 'java':
return JavaGenerator(storage, idl)
if self.generator_name.lower() == 'bridge':
return BridgeGenerator(storage, idl)
else:
raise Exception("Unknown generator for testing: %s",
self.generator_name.lower())
def run_test_cases(self, checker: unittest.TestCase):
for test in self.test_cases:
with checker.subTest(idl=test.input_idl):
storage = TestCaseStorage(test, checker)
with open(os.path.join(TESTS_DIR, test.input_idl), 'rt') as stream:
idl = CreateParser().parse(stream.read())
generator = self._create_generator(storage, idl)
generator.render(dry_run=False)
checker.assertEqual(storage.checked_files, set(
map(lambda x: x.file_name, test.outputs)))
def build_tests(yaml_data) -> List[GeneratorTest]:
"""
Transforms the YAML dictonary (Dict[str, Dict[str, Dict[str,str]]]) into
a generator test structure.
"""
result = []
for key, test_cases in yaml_data.items():
generator = GeneratorTest(generator_name=key)
generator.add_test_cases(test_cases)
result.append(generator)
return result
class TestGenerators(unittest.TestCase):
def test_generators(self):
with open(os.path.join(TESTS_DIR, "available_tests.yaml"), 'rt') as stream:
yaml_data = yaml.safe_load(stream)
for test in build_tests(yaml_data):
with self.subTest(generator=test.generator_name):
test.run_test_cases(self)
if __name__ == '__main__':
if 'IDL_GOLDEN_REGENERATE' in os.environ:
# run with `IDL_GOLDEN_REGENERATE=1` to cause a regeneration of test
# data. Then one can use `git diff` to see if the deltas make sense
REGENERATE_GOLDEN_IMAGES = True
unittest.main()