diff --git a/ebuild/cli/commands.py b/ebuild/cli/commands.py index ad039bbb..53765193 100644 --- a/ebuild/cli/commands.py +++ b/ebuild/cli/commands.py @@ -2281,6 +2281,9 @@ def new(log: Logger, project_name: str, template_name: str, board_name: str, "build.yaml.template": project_dir / "build.yaml", "eos.yaml.template": project_dir / "eos.yaml", "README.md.template": project_dir / "README.md", + # Every template's build.yaml declares a test target built from + # tests/test_main.c; without this file `ebuild build` fails at once. + "test_main.c.template": project_dir / "tests" / "test_main.c", } for template_file, output_path in file_mapping.items(): @@ -2293,6 +2296,7 @@ def new(log: Logger, project_name: str, template_name: str, board_name: str, for key, val in replacements.items(): content = content.replace(key, val) + output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(content, encoding="utf-8") log.success(f" {output_path.relative_to(parent)}") diff --git a/templates/safety-critical/build.yaml.template b/templates/safety-critical/build.yaml.template index 01317eb0..3222e520 100644 --- a/templates/safety-critical/build.yaml.template +++ b/templates/safety-critical/build.yaml.template @@ -24,12 +24,6 @@ targets: - eos depends: [] -firmware: - board: {{BOARD_NAME}} - core: {{CORE}} - tick_rate: 1000 - watchdog_ms: 100 - - name: test_{{PROJECT_NAME}} type: test sources: @@ -39,3 +33,9 @@ firmware: uses: - eos depends: [] + +firmware: + board: {{BOARD_NAME}} + core: {{CORE}} + tick_rate: 1000 + watchdog_ms: 100 diff --git a/tests/unit/test_new_scaffold.py b/tests/unit/test_new_scaffold.py new file mode 100644 index 00000000..385a0809 --- /dev/null +++ b/tests/unit/test_new_scaffold.py @@ -0,0 +1,26 @@ +"""`ebuild new` must write every source its generated build.yaml declares.""" +from pathlib import Path + +import pytest +import yaml +from click.testing import CliRunner + +from ebuild.cli.commands import cli + +TEMPLATES = ["bare-metal", "ble-sensor", "rtos-app", "linux-app", + "secure-boot", "safety-critical"] + + +@pytest.mark.parametrize("template", TEMPLATES) +def test_new_writes_every_declared_source(tmp_path: Path, template: str) -> None: + result = CliRunner().invoke( + cli, ["new", "proj", "--template", template, "--board", "stm32f4", + "--output-dir", str(tmp_path)]) + assert result.exit_code == 0, result.output + project = tmp_path / "proj" + config = yaml.safe_load((project / "build.yaml").read_text(encoding="utf-8")) + declared = [src for target in config["targets"] for src in target.get("sources", [])] + assert declared, "template declares no sources" + missing = [src for src in declared if not (project / src).is_file()] + assert not missing, f"{template}: build.yaml declares missing sources {missing}" + assert "{{" not in (project / "tests" / "test_main.c").read_text(encoding="utf-8")