| #!/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 sys |
| import unittest |
| from difflib import unified_diff |
| from typing import List, Optional |
| |
| try: |
| from matter_idl.matter_idl_parser import CreateParser |
| except ImportError: |
| |
| sys.path.append(os.path.abspath( |
| os.path.join(os.path.dirname(__file__), '..'))) |
| from matter_idl.matter_idl_parser import CreateParser |
| |
| from matter_idl.generators import GeneratorStorage |
| from matter_idl.generators.idl import IdlGenerator |
| from matter_idl.matter_idl_types import Idl |
| |
| |
| class TestCaseStorage(GeneratorStorage): |
| def __init__(self): |
| super().__init__() |
| self.content: Optional[str] = None |
| |
| def get_existing_data(self, relative_path: str): |
| # Force re-generation each time |
| return None |
| |
| def write_new_data(self, relative_path: str, content: str): |
| if self.content: |
| raise Exception( |
| "Unexpected extra data: single file generation expected") |
| self.content = content |
| |
| |
| def ReadMatterIdl(repo_path: str) -> str: |
| path = os.path.join(os.path.dirname(__file__), "../../..", repo_path) |
| with open(path, "rt") as stream: |
| return stream.read() |
| |
| |
| def ParseMatterIdl(repo_path: str, skip_meta: bool) -> Idl: |
| return CreateParser(skip_meta=skip_meta).parse(ReadMatterIdl(repo_path)) |
| |
| |
| def RenderAsIdlTxt(idl: Idl) -> str: |
| storage = TestCaseStorage() |
| IdlGenerator(storage=storage, idl=idl).render(dry_run=False) |
| return storage.content or "" |
| |
| |
| def SkipLeadingComments(txt: str, also_strip: List[str] = list()) -> str: |
| """Skips leading lines starting with // in a file. """ |
| lines = txt.split("\n") |
| idx = 0 |
| while lines[idx].startswith("//") or not lines[idx]: |
| idx = idx + 1 |
| |
| result = "\n".join(lines[idx:]) |
| |
| for s in also_strip: |
| result = result.replace(s, "") |
| |
| return result |
| |
| |
| class TestIdlRendering(unittest.TestCase): |
| def assertTextEqual(self, a: str, b: str): |
| if a == b: |
| # seems the same. This will just pass |
| self.assertEqual(a, b) |
| return |
| |
| delta = unified_diff(a.splitlines(keepends=True), |
| b.splitlines(keepends=True), |
| fromfile='actual.matter', |
| tofile='expected.matter', |
| ) |
| self.assertEqual(a, b, '\n' + ''.join(delta)) |
| |
| def test_client_clusters(self): |
| # IDL renderer was updated to have IDENTICAL output for client side |
| # cluster rendering, so this diff will be verbatim |
| # |
| # Comparison made text-mode so that meta-data is read and doc-comments are |
| # available |
| |
| path = "src/controller/data_model/controller-clusters.matter" |
| |
| # Files MUST be identical except the header comments which are different |
| original = SkipLeadingComments(ReadMatterIdl(path), also_strip=[ |
| " // NOTE: Default/not specifically set"]) |
| generated = SkipLeadingComments(RenderAsIdlTxt( |
| ParseMatterIdl(path, skip_meta=False))) |
| |
| self.assertTextEqual(original, generated) |
| |
| def test_app_rendering(self): |
| # When endpoints are involved, default value formatting is lost |
| # (e.g. "0x0000" becomes "0") and ordering of emitted events is not preserved |
| # because the events are a |
| |
| # as such, this test validates that parsing + generating + re-parsing results |
| # in the same data being parsed |
| test_paths = [ |
| "examples/lock-app/lock-common/lock-app.matter", |
| "examples/lighting-app/lighting-common/lighting-app.matter", |
| "examples/all-clusters-app/all-clusters-common/all-clusters-app.matter", |
| "examples/thermostat/thermostat-common/thermostat.matter", |
| ] |
| |
| for path in test_paths: |
| idl = ParseMatterIdl(path, skip_meta=True) |
| txt = RenderAsIdlTxt(idl) |
| idl2 = CreateParser(skip_meta=True).parse(txt) |
| |
| # checks that data types and content is the same |
| self.assertEqual(idl, idl2) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |