Skip to content

Commit

Permalink
Add regression tests for config processing
Browse files Browse the repository at this point in the history
Add regression tests at the public interface level so we can rework the
config processing code and have some confidence we haven't broken anything.
  • Loading branch information
rwalton-arm committed Dec 9, 2020
1 parent 2ab99a1 commit 53962ab
Show file tree
Hide file tree
Showing 2 changed files with 288 additions and 24 deletions.
1 change: 1 addition & 0 deletions news/20201208190734.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add regression tests for config module.
311 changes: 287 additions & 24 deletions tests/build/test_generate_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,294 @@
# Copyright (C) 2020 Arm Mbed. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
from unittest import TestCase, mock
import json

import pytest

from mbed_tools.project import MbedProgram
from mbed_tools.build import generate_config


class TestGenerateConfig(TestCase):
@mock.patch("mbed_tools.build.config.MbedProgram")
@mock.patch("mbed_tools.build.config.get_target_by_name")
@mock.patch("mbed_tools.build.config.generate_mbed_config_cmake_file")
@mock.patch("mbed_tools.build.config.assemble_config")
@mock.patch("mbed_tools.build.config.write_file")
def test_collaborators_called_with_corrrect_arguments(
self, write_file, assemble_config, gen_config_cmake, get_target_by_name, mbed_program
):
program = mbed_program.from_existing()

generate_config("K64F", "GCC_ARM", program)

get_target_by_name.assert_called_once_with("K64F", program.mbed_os.targets_json_file)
assemble_config.assert_called_once_with(
get_target_by_name.return_value, program.root, program.files.app_config_file,
)
gen_config_cmake.assert_called_once_with(
"K64F", get_target_by_name.return_value, assemble_config.return_value, "GCC_ARM"
)
write_file.assert_called_once_with(
program.files.cmake_config_file.parent, program.files.cmake_config_file.name, gen_config_cmake.return_value,
)
TARGETS = ["K64F", "NUCLEO_F401RE"]

TARGET_DATA = {
"bootloader_supported": True,
"c_lib": "std",
"components": ["FLASHIAP", "SD"],
"config": {
"xip-enable": {
"help": "Enable Execute In Place (XIP) on this "
"target. Value is only significant if the "
"board has executable external storage such "
"as QSPIF. If this is enabled, customize "
"the linker file to choose what text "
"segments are placed on external storage",
"value": False,
}
},
"core": "Cortex-M4F",
"default_toolchain": "ARM",
"detect_code": ["0240"],
"device_has": ["TRNG"],
"device_name": "MK64FN1M0xxx12",
"extra_labels": ["FRDM", "Freescale"],
"features": ["PSA"],
"is_disk_virtual": True,
"labels": ["CORTEX", "CORTEX_M"],
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "MBED_SPLIT_HEAP", "MBED_TICKLESS"],
"printf_lib": "minimal-printf",
"release_versions": ["5"],
"static_memory_defines": True,
"supported_application_profiles": ["full", "bare-metal"],
"supported_c_libs": {"arm": ["std", "small"], "gcc_arm": ["std", "small"], "iar": ["std"]},
"supported_form_factors": ["ARDUINO"],
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
"trustzone": False,
}


def create_mbed_lib_json(lib_json_path, name, **kwargs):
lib_json_path.parent.mkdir(parents=True, exist_ok=True)
lib_json_path.write_text(json.dumps({"name": name, **kwargs}))


def create_mbed_app_json(root, **kwargs):
(root / "mbed_app.json").write_text(json.dumps(kwargs))


@pytest.fixture
def program(tmp_path):
prog = MbedProgram.from_new(tmp_path / "test-prog")
# Overwrite the default mbed_app.json so it doesn't mess with our test env
prog.files.app_config_file.write_text(json.dumps({"": ""}))
# Create program mbed-os directory and fake targets.json
prog.mbed_os.root.mkdir(parents=True)
prog.mbed_os.targets_json_file.parent.mkdir(exist_ok=True, parents=True)
prog.mbed_os.targets_json_file.write_text(json.dumps({target: TARGET_DATA for target in TARGETS}))
return prog


@pytest.fixture(
params=[(TARGETS[0], TARGETS[0]), (TARGETS[1], TARGETS[1]), (TARGETS[0], "*")],
ids=lambda fixture_val: f"target: {fixture_val[0]}, filter: {fixture_val[1]}",
)
def matching_target_and_filter(request):
return request.param


def test_target_and_toolchain_collected(program):
target = "K64F"
toolchain = "GCC_ARM"

generate_config(target, toolchain, program)

config_text = program.files.cmake_config_file.read_text()

assert target in config_text
assert toolchain in config_text


def test_config_param_from_mbed_lib_processed_with_default_name_mangling(program):
create_mbed_lib_json(
program.mbed_os.root / "platform" / "mbed_lib.json",
"platform",
config={
"stdio-convert-newlines": {
"help": "Enable conversion to standard newlines on stdin/stdout/stderr",
"value": True,
}
},
)

generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES" in config_text


def test_config_param_from_mbed_lib_processed_with_user_set_name(program):
create_mbed_lib_json(
program.mbed_os.root / "platform" / "mbed_lib.json",
"platform",
config={
"stdio-convert-newlines": {
"help": "Enable conversion to standard newlines on stdin/stdout/stderr",
"value": True,
"macro_name": "ENABLE_NEWLINES",
}
},
)

generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "ENABLE_NEWLINES" in config_text


def test_config_param_from_target_processed_with_default_name_mangling(program):
generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "MBED_CONF_TARGET_XIP_ENABLE=0" in config_text


def test_macros_from_lib_collected(program):
macros = ["NS_USE_EXTERNAL_MBED_TLS"]
create_mbed_lib_json(program.mbed_os.root / "connectivity" / "mbed_lib.json", "nanostack", macros=macros)

generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

for macro in macros:
assert macro in config_text


def test_macros_from_target_collected(program):
generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

for macro in TARGET_DATA["macros"]:
assert macro in config_text


def test_target_labels_collected_as_defines(program):
generate_config("K64F", "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

for label in TARGET_DATA["labels"] + TARGET_DATA["extra_labels"]:
assert f"TARGET_{label}" in config_text

for feature in TARGET_DATA["features"]:
assert f"FEATURE_{feature}=1" in config_text

for device in TARGET_DATA["device_has"]:
assert f"DEVICE_{device}=1" in config_text

for form_factor in TARGET_DATA["supported_form_factors"]:
assert f"TARGET_FF_{form_factor}" in config_text


def test_overrides_lib_config_param_from_app(matching_target_and_filter, program):
target, target_filter = matching_target_and_filter
create_mbed_lib_json(
program.mbed_os.root / "mbed_lib.json", "platform", config={"stdio-baud-rate": {"value": 9600}},
)

create_mbed_app_json(program.root, target_overrides={target_filter: {"platform.stdio-baud-rate": 115200}})
generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "MBED_CONF_PLATFORM_STDIO_BAUD_RATE=115200" in config_text


def test_overrides_target_config_param_from_app(matching_target_and_filter, program):
target, target_filter = matching_target_and_filter
create_mbed_app_json(program.root, target_overrides={target_filter: {"target.xip-enable": True}})

generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "MBED_CONF_TARGET_XIP_ENABLE=1" in config_text


@pytest.mark.parametrize(
"config_param, config_param_value, expected_output",
[
("target.c_lib", "super", 'MBED_C_LIB "super"'),
("target.printf_lib", "maximal-printf", 'MBED_PRINTF_LIB "maximal-printf"'),
],
)
def test_overrides_target_non_config_params_from_app(
matching_target_and_filter, config_param, config_param_value, expected_output, program
):
target, target_filter = matching_target_and_filter
create_mbed_app_json(program.root, target_overrides={target_filter: {config_param: config_param_value}})

generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert expected_output in config_text


def test_overrides_config_param_from_same_lib(matching_target_and_filter, program):
target, target_filter = matching_target_and_filter
create_mbed_lib_json(
program.mbed_os.root / "mbed_lib.json",
"platform",
config={"stdio-baud-rate": {"value": 9600}},
target_overrides={target_filter: {"stdio-baud-rate": 115200}},
)

generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert "MBED_CONF_PLATFORM_STDIO_BAUD_RATE=115200" in config_text


@pytest.mark.parametrize(
"config_param, config_param_value, expected_output",
[
("target.macros_add", ["ENABLE_BOBBINS"], TARGET_DATA["macros"] + ["ENABLE_BOBBINS"]),
("target.extra_labels_add", ["EXTRA_LABEL_BOBBINS"], TARGET_DATA["extra_labels"] + ["EXTRA_LABEL_BOBBINS"]),
("target.features_add", ["FEATURE_BOBBINS"], TARGET_DATA["features"] + ["FEATURE_BOBBINS"]),
("target.components_add", ["COMPONENT_BOBBINS"], TARGET_DATA["components"] + ["COMPONENT_BOBBINS"]),
],
)
def test_target_list_params_can_be_added_to(
matching_target_and_filter, config_param, config_param_value, expected_output, program
):
target, target_filter = matching_target_and_filter
create_mbed_app_json(
program.root, target_overrides={target_filter: {config_param: config_param_value}},
)

generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

for expected in expected_output:
assert expected in config_text


@pytest.mark.parametrize(
"config_param, config_param_value, expected_output",
[
("target.macros_remove", [TARGET_DATA["macros"][0]], TARGET_DATA["macros"][0]),
("target.extra_labels_remove", [TARGET_DATA["extra_labels"][0]], TARGET_DATA["extra_labels"][0]),
("target.features_remove", [TARGET_DATA["features"][0]], TARGET_DATA["features"][0]),
("target.components_remove", [TARGET_DATA["components"][0]], TARGET_DATA["components"][0]),
],
)
def test_target_list_params_can_be_removed(
matching_target_and_filter, config_param, config_param_value, expected_output, program
):
target, target_filter = matching_target_and_filter
create_mbed_app_json(
program.root, target_overrides={target_filter: {config_param: config_param_value}},
)

generate_config(target, "GCC_ARM", program)

config_text = program.files.cmake_config_file.read_text()

assert expected_output not in config_text


def test_raises_when_attempting_to_override_nonexistent_param(matching_target_and_filter, program):
target, target_filter = matching_target_and_filter
create_mbed_app_json(
program.root, target_overrides={target_filter: {"target.some-nonexistent-config-param": 999999}}
)

with pytest.raises(ValueError):
generate_config(target, "GCC_ARM", program)

0 comments on commit 53962ab

Please sign in to comment.