#!/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-mbedtls', 'openiotsdk-shell-mbedtls' ] 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()