| #!/usr/bin/env python3 |
| |
| # Copyright (c) 2021 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 difflib |
| import os |
| import subprocess |
| import sys |
| import unittest |
| from typing import List |
| |
| SCRIPT_ROOT = os.path.dirname(__file__) |
| |
| |
| def build_expected_output(source: str, root: str, out: str) -> List[str]: |
| with open(os.path.join(SCRIPT_ROOT, source), 'rt') as f: |
| for line in f.readlines(): |
| yield line.replace("{root}", root).replace("{out}", out) |
| |
| |
| def build_actual_output(root: str, out: str, args: List[str]) -> List[str]: |
| # Fake out that we have a project root |
| binary = os.path.join(SCRIPT_ROOT, 'build_examples.py') |
| |
| runenv = {} |
| runenv.update(os.environ) |
| runenv.update({ |
| 'PW_PROJECT_ROOT': root, |
| 'ANDROID_NDK_HOME': 'TEST_ANDROID_NDK_HOME', |
| 'ANDROID_HOME': 'TEST_ANDROID_HOME', |
| 'TIZEN_SDK_ROOT': 'TEST_TIZEN_SDK_ROOT', |
| 'TIZEN_SDK_SYSROOT': 'TEST_TIZEN_SDK_SYSROOT', |
| 'TELINK_ZEPHYR_SDK_DIR': 'TELINK_ZEPHYR_SDK_DIR', |
| 'SYSROOT_AARCH64': 'SYSROOT_AARCH64', |
| 'NXP_K32W0_SDK_ROOT': 'TEST_NXP_K32W0_SDK_ROOT', |
| 'IMX_SDK_ROOT': 'IMX_SDK_ROOT', |
| 'TI_SYSCONFIG_ROOT': 'TEST_TI_SYSCONFIG_ROOT', |
| 'JAVA_PATH': 'TEST_JAVA_PATH', |
| }) |
| |
| retval = subprocess.run([ |
| binary, |
| '--log-level', 'FATAL', |
| '--dry-run', |
| '--repo', root, |
| '--out-prefix', out, |
| ] + args, stdout=subprocess.PIPE, check=True, encoding='UTF-8', env=runenv) |
| |
| result = [line + '\n' for line in retval.stdout.split('\n')] |
| |
| # ensure a single terminating newline: easier to edit since autoformat |
| # often strips ending double newlines on text files |
| while result[-1] == '\n': |
| result = result[:-1] |
| |
| return result |
| |
| |
| class TestBuilder(unittest.TestCase): |
| |
| def assertCommandOutput(self, expected_file: str, args: List[str]): |
| ROOT = '/TEST/BUILD/ROOT' |
| OUT = '/OUTPUT/DIR' |
| |
| expected = [line for line in build_expected_output(expected_file, ROOT, OUT)] |
| actual = [line for line in build_actual_output(ROOT, OUT, args)] |
| |
| diffs = [line for line in difflib.unified_diff(expected, actual)] |
| |
| if diffs: |
| reference = os.path.basename(expected_file) + '.actual' |
| with open(reference, 'wt') as fo: |
| for line in build_actual_output(ROOT, OUT, args): |
| fo.write(line.replace(ROOT, '{root}').replace(OUT, '{out}')) |
| |
| msg = "DIFFERENCE between expected and generated output in %s\n" % expected_file |
| msg += "Expected file can be found in %s" % reference |
| for line in diffs: |
| msg += ("\n " + line.replace(ROOT, |
| '{root}').replace(OUT, '{out}').strip()) |
| self.fail(msg) |
| |
| @unittest.skipUnless(sys.platform == 'linux', 'Build on linux test') |
| @unittest.skipUnless(os.uname().machine == 'x86_64', 'Validation x64 and crosscompile, requires linux x64') |
| def test_linux64_targets(self): |
| self.assertCommandOutput( |
| os.path.join('testdata', 'all_targets_linux_x64.txt'), |
| 'targets'.split(' ') |
| ) |
| |
| def test_general_dry_runs(self): |
| # A sampling of targets and variants to validate that |
| # build options do not change too much |
| TARGETS = [ |
| 'esp32-devkitc-light-rpc', |
| 'esp32-m5stack-all-clusters-minimal-rpc-ipv6only', |
| 'android-arm64-chip-tool', |
| 'nrf-nrf52840dk-pump', |
| 'efr32-brd4161a-light-rpc-no-version', |
| 'openiotsdk-lock', |
| 'openiotsdk-shell' |
| ] |
| |
| for target in TARGETS: |
| expected = os.path.join('testdata', f'dry_run_{target}.txt') |
| self.assertCommandOutput(expected, f'--target {target} --dry-run build'.split(' ')) |
| |
| @unittest.skipUnless(sys.platform == 'linux', 'Build on linux test') |
| @unittest.skipUnless(os.uname().machine == 'x86_64', 'Validation x64 and crosscompile, requires linux x64') |
| def test_linux_dry_runs(self): |
| TARGETS = [ |
| 'linux-arm64-chip-tool-ipv6only-clang', |
| 'linux-arm64-ota-requestor-nodeps-ipv6only', |
| 'linux-x64-all-clusters-coverage', |
| ] |
| |
| for target in TARGETS: |
| expected = os.path.join('testdata', f'dry_run_{target}.txt') |
| self.assertCommandOutput(expected, f'--target {target} --dry-run build'.split(' ')) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |