mirror of https://github.com/ARMmbed/mbed-os.git
339 lines
14 KiB
Python
339 lines
14 KiB
Python
#
|
|
# Copyright (c) 2020-2021 Arm Limited and Contributors. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import contextlib
|
|
import os
|
|
import pathlib
|
|
|
|
from tempfile import TemporaryDirectory
|
|
from unittest import TestCase, mock
|
|
|
|
from click.testing import CliRunner
|
|
|
|
import sys
|
|
print(sys.path)
|
|
|
|
from mbed_tools.cli.build import build
|
|
from mbed_tools.project._internal.project_data import BUILD_DIR
|
|
from mbed_tools.build.config import CMAKE_CONFIG_FILE
|
|
|
|
|
|
DEFAULT_BUILD_ARGS = ["-t", "GCC_ARM", "-m", "K64F"]
|
|
DEFAULT_BUILD_SUBDIR = pathlib.Path("K64F", "develop", "GCC_ARM")
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def mock_project_directory(
|
|
program, mbed_config_exists=False, build_tree_exists=False, build_subdir=DEFAULT_BUILD_SUBDIR
|
|
):
|
|
with TemporaryDirectory() as tmp_dir:
|
|
root = pathlib.Path(tmp_dir, "test-project")
|
|
root.mkdir()
|
|
program.root = root
|
|
program.files.cmake_build_dir = root / BUILD_DIR / build_subdir
|
|
program.files.cmake_config_file = root / BUILD_DIR / build_subdir / CMAKE_CONFIG_FILE
|
|
if mbed_config_exists:
|
|
program.files.cmake_config_file.parent.mkdir(exist_ok=True, parents=True)
|
|
program.files.cmake_config_file.touch(exist_ok=True)
|
|
|
|
if build_tree_exists:
|
|
program.files.cmake_build_dir.mkdir(exist_ok=True, parents=True)
|
|
|
|
yield
|
|
|
|
|
|
@mock.patch("mbed_tools.cli.build.generate_build_system")
|
|
@mock.patch("mbed_tools.cli.build.build_project")
|
|
@mock.patch("mbed_tools.cli.build.MbedProgram")
|
|
@mock.patch("mbed_tools.cli.build.generate_config")
|
|
class TestBuildCommand(TestCase):
|
|
def test_searches_for_mbed_program_at_default_project_path(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
runner = CliRunner()
|
|
runner.invoke(build, DEFAULT_BUILD_ARGS)
|
|
|
|
mbed_program.from_existing.assert_called_once_with(pathlib.Path(os.getcwd()), DEFAULT_BUILD_SUBDIR)
|
|
|
|
def test_searches_for_mbed_program_at_user_defined_project_root(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
project_path = "my-blinky"
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-p", project_path, *DEFAULT_BUILD_ARGS])
|
|
|
|
mbed_program.from_existing.assert_called_once_with(pathlib.Path(project_path), DEFAULT_BUILD_SUBDIR)
|
|
|
|
def test_calls_generate_build_system_if_build_tree_nonexistent(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(program, mbed_config_exists=True, build_tree_exists=False):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, DEFAULT_BUILD_ARGS)
|
|
|
|
generate_build_system.assert_called_once_with(program.root, program.files.cmake_build_dir, "develop")
|
|
|
|
def test_generate_config_called_if_config_script_nonexistent(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(
|
|
program, mbed_config_exists=False, build_subdir=pathlib.Path("K64F", "develop", "GCC_ARM")
|
|
):
|
|
target = "k64f"
|
|
toolchain = "gcc_arm"
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target])
|
|
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
|
|
def test_raises_if_gen_config_toolchain_not_passed_when_required(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(program, mbed_config_exists=False):
|
|
target = "k64f"
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(build, ["-m", target])
|
|
|
|
self.assertIsNotNone(result.exception)
|
|
self.assertRegex(result.output, "--toolchain")
|
|
|
|
def test_raises_if_gen_config_target_not_passed_when_required(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(program, mbed_config_exists=False):
|
|
toolchain = "gcc_arm"
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(build, ["-t", toolchain])
|
|
|
|
self.assertIsNotNone(result.exception)
|
|
self.assertRegex(result.output, "--mbed-target")
|
|
|
|
def test_raises_if_target_identifier_not_int(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
target = "K64F[foo]"
|
|
|
|
result = CliRunner().invoke(build, ["-m", target, "-t", "gcc_arm"])
|
|
self.assertIsNotNone(result.exception)
|
|
self.assertRegex(result.output, "ID")
|
|
|
|
def test_raises_if_target_identifier_negative(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
target = "K64F[-1]"
|
|
|
|
result = CliRunner().invoke(build, ["-m", target, "-t", "gcc_arm"])
|
|
self.assertIsNotNone(result.exception)
|
|
self.assertRegex(result.output, "ID")
|
|
|
|
def test_build_system_regenerated_when_mbed_os_path_passed(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(
|
|
program,
|
|
mbed_config_exists=True,
|
|
build_tree_exists=True,
|
|
build_subdir=pathlib.Path("K64F", "develop", "GCC_ARM"),
|
|
):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
toolchain = "gcc_arm"
|
|
target = "k64f"
|
|
mbed_os_path = "./extern/mbed-os"
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target, "--mbed-os-path", mbed_os_path])
|
|
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
generate_build_system.assert_called_once_with(program.root, program.files.cmake_build_dir, "develop")
|
|
|
|
def test_custom_targets_location_used_when_passed(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(program, mbed_config_exists=True, build_tree_exists=True):
|
|
toolchain = "gcc_arm"
|
|
target = "k64f"
|
|
custom_targets_json_path = pathlib.Path("custom", "custom_targets.json")
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target, "--custom-targets-json", custom_targets_json_path])
|
|
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
self.assertEqual(program.files.custom_targets_json, custom_targets_json_path)
|
|
|
|
def test_app_config_used_when_passed(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(program, mbed_config_exists=True, build_tree_exists=True):
|
|
toolchain = "gcc_arm"
|
|
target = "k64f"
|
|
app_config_path = pathlib.Path("alternative_config.json")
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target, "--app-config", app_config_path])
|
|
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
self.assertEqual(program.files.app_config_file, app_config_path)
|
|
|
|
def test_profile_used_when_passed(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
mbed_program.reset_mock() # clear call count from previous line
|
|
|
|
with mock_project_directory(program, mbed_config_exists=True, build_tree_exists=True):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
toolchain = "gcc_arm"
|
|
target = "k64f"
|
|
profile = "release"
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target, "--profile", profile])
|
|
|
|
mbed_program.from_existing.assert_called_once_with(
|
|
pathlib.Path(os.getcwd()),
|
|
pathlib.Path(target.upper(), profile, toolchain.upper())
|
|
)
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
generate_build_system.assert_called_once_with(program.root, program.files.cmake_build_dir, profile)
|
|
|
|
def test_build_folder_removed_when_clean_flag_passed(
|
|
self, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
program = mbed_program.from_existing()
|
|
with mock_project_directory(
|
|
program,
|
|
mbed_config_exists=True,
|
|
build_tree_exists=True,
|
|
build_subdir=pathlib.Path("K64F", "develop", "GCC_ARM"),
|
|
):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
toolchain = "gcc_arm"
|
|
target = "k64f"
|
|
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["-t", toolchain, "-m", target, "-c"])
|
|
|
|
generate_config.assert_called_once_with(target.upper(), toolchain.upper(), program)
|
|
generate_build_system.assert_called_once_with(program.root, program.files.cmake_build_dir, "develop")
|
|
self.assertFalse(program.files.cmake_build_dir.exists())
|
|
|
|
@mock.patch("mbed_tools.cli.build.flash_binary")
|
|
@mock.patch("mbed_tools.cli.build.find_all_connected_devices")
|
|
def test_build_flash_options_bin_target(
|
|
self,
|
|
mock_find_devices,
|
|
flash_binary,
|
|
generate_config,
|
|
mbed_program,
|
|
build_project,
|
|
generate_build_system,
|
|
):
|
|
# A target with bin images does not need OUTPUT_EXT defined
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
mock_find_devices.return_value = [mock.MagicMock()]
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["--flash", *DEFAULT_BUILD_ARGS])
|
|
call_args = flash_binary.call_args
|
|
args, kwargs = call_args
|
|
flash_binary.assert_called_once_with(args[0], args[1], args[2], args[3], False)
|
|
|
|
@mock.patch("mbed_tools.cli.build.flash_binary")
|
|
@mock.patch("mbed_tools.cli.build.find_all_connected_devices")
|
|
def test_build_flash_options_hex_target(
|
|
self,
|
|
mock_find_devices,
|
|
flash_binary,
|
|
generate_config,
|
|
mbed_program,
|
|
build_project,
|
|
generate_build_system,
|
|
):
|
|
generate_config.return_value = [{"OUTPUT_EXT": "hex"}, mock.MagicMock()]
|
|
mock_find_devices.return_value = [mock.MagicMock()]
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["--flash", *DEFAULT_BUILD_ARGS])
|
|
call_args = flash_binary.call_args
|
|
args, kwargs = call_args
|
|
flash_binary.assert_called_once_with(args[0], args[1], args[2], args[3], True)
|
|
|
|
@mock.patch("mbed_tools.cli.build.flash_binary")
|
|
@mock.patch("mbed_tools.cli.build.find_all_connected_devices")
|
|
def test_build_flash_both_two_devices(
|
|
self,
|
|
mock_find_devices,
|
|
flash_binary,
|
|
generate_config,
|
|
mbed_program,
|
|
build_project,
|
|
generate_build_system,
|
|
):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
mock_find_devices.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["--flash", *DEFAULT_BUILD_ARGS])
|
|
self.assertEqual(flash_binary.call_count, 2)
|
|
|
|
@mock.patch("mbed_tools.cli.build.flash_binary")
|
|
@mock.patch("mbed_tools.cli.build.find_connected_device")
|
|
def test_build_flash_only_identifier_device(
|
|
self,
|
|
mock_find_device,
|
|
flash_binary,
|
|
generate_config,
|
|
mbed_program,
|
|
build_project,
|
|
generate_build_system,
|
|
):
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
mock_find_device.return_value = mock.MagicMock()
|
|
runner = CliRunner()
|
|
runner.invoke(build, ["--flash", "-m", "K64F[1]", "-t", "GCC_ARM"])
|
|
self.assertEqual(flash_binary.call_count, 1)
|
|
|
|
@mock.patch("mbed_tools.cli.build.terminal")
|
|
@mock.patch("mbed_tools.cli.build.find_connected_device")
|
|
def test_sterm_is_started_when_flag_passed(
|
|
self, mock_find_device, mock_terminal, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
target = "K64F"
|
|
serial_port = "tty.k64f"
|
|
baud = 115200
|
|
mock_find_device.return_value = mock.Mock(serial_port=serial_port)
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
CliRunner().invoke(build, ["-m", target, "-t", "gcc_arm", "--sterm", "--baudrate", baud])
|
|
|
|
mock_find_device.assert_called_once_with(target, None)
|
|
mock_terminal.run.assert_called_once_with(serial_port, baud)
|
|
|
|
@mock.patch("mbed_tools.cli.build.terminal")
|
|
@mock.patch("mbed_tools.cli.build.find_connected_device")
|
|
def test_raises_if_device_does_not_have_serial_port_and_sterm_flag_given(
|
|
self, mock_find_device, mock_terminal, generate_config, mbed_program, build_project, generate_build_system
|
|
):
|
|
target = "K64F"
|
|
serial_port = None
|
|
mock_find_device.return_value = mock.Mock(serial_port=serial_port)
|
|
generate_config.return_value = [mock.MagicMock(), mock.MagicMock()]
|
|
|
|
output = CliRunner().invoke(build, ["-m", target, "-t", "gcc_arm", "--sterm"])
|
|
self.assertEqual(type(output.exception), SystemExit)
|
|
mock_terminal.assert_not_called()
|