blob: 9f40b111bff96fe1319ad57fa20e2310f507d1a7 [file] [log] [blame]
#!/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()