Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion platformio/builder/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,15 @@
)

AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS))
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))
if "compiledb" in COMMAND_LINE_TARGETS:
# `pio run -t compiledb -t __test` (issue #4934): "__test" is passed only
# to include test sources in the compilation database. Don't alias it to
# the default build targets — a full build would try to link every test
# suite (each with its own `main()`) into one program and fail, while
# compiledb generation itself never compiles or links anything.
env.Alias("__test", [])
else:
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))

env.ProcessDelayedActions()

Expand Down
19 changes: 19 additions & 0 deletions platformio/builder/tools/piotest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import os

from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error

from platformio.builder.tools import piobuild
from platformio.test.result import TestSuite
from platformio.test.runners.factory import TestRunnerFactory
Expand All @@ -26,6 +28,23 @@ def ConfigureTestTarget(env):
)
env.Prepend(CPPPATH=["$PROJECT_TEST_DIR"])

if "PIOTEST_RUNNING_NAME" not in env and "compiledb" in COMMAND_LINE_TARGETS:
# A compilation database is being generated without a specific test
# suite selected (`pio run -t compiledb -t __test`, issue #4934).
# The default filter above only matches sources directly in the test
# dir, so nested `test_*/` suites — the documented layout — would
# produce "Nothing to build". Include every test suite recursively:
# unlike a real test build, compiledb never links, so the multiple
# `main()` definitions across suites are not a problem.
env.Append(PIOTEST_SRC_FILTER=[f"+<test_*{os.path.sep}>"])
test_dir = env.subst("$PROJECT_TEST_DIR")
if os.path.isdir(test_dir):
for item in sorted(os.listdir(test_dir)):
if item.startswith("test_") and os.path.isdir(
os.path.join(test_dir, item)
):
env.Prepend(CPPPATH=[os.path.join("$PROJECT_TEST_DIR", item)])

if "PIOTEST_RUNNING_NAME" in env:
test_name = env["PIOTEST_RUNNING_NAME"]
while True:
Expand Down
82 changes: 82 additions & 0 deletions tests/commands/test_run_compiledb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# 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 json

from platformio.run.cli import cli as cmd_run


def _make_project_with_tests(tmpdir, extra_ini=""):
tmpdir.join("platformio.ini").write("""
[env:native]
platform = native
%s
""" % extra_ini)
tmpdir.mkdir("src").join("calc.c").write("""
int add(int a, int b) { return a + b; }
""")
tmpdir.mkdir("test").mkdir("test_calc").join("test_add.c").write("""
int add(int a, int b);
int main(void) { return add(1, 2) == 3 ? 0 : 1; }
""")


def _compiledb_files(tmpdir):
with open(str(tmpdir.join("compile_commands.json")), encoding="utf8") as fp:
return [entry["file"] for entry in json.load(fp)]


def test_compiledb_includes_test_sources(clirunner, validate_cliresult, tmpdir):
# Regression test for https://github.com/platformio/platformio-core/issues/4934
# `pio run -t compiledb -t __test` used to fail with "Nothing to build"
# for the documented `test/test_*/` layout, leaving test sources (and
# test-framework headers like unity.h) out of the compilation database.
_make_project_with_tests(tmpdir)
result = clirunner.invoke(
cmd_run,
["--project-dir", str(tmpdir), "-t", "compiledb", "-t", "__test"],
)
validate_cliresult(result)

files = _compiledb_files(tmpdir)
assert any(f.endswith("test_add.c") for f in files), files


def test_compiledb_with_tests_and_src(clirunner, validate_cliresult, tmpdir):
# With `test_build_src = yes`, both the test suites and the production
# sources should land in the compilation database.
_make_project_with_tests(tmpdir, extra_ini="test_build_src = yes")
result = clirunner.invoke(
cmd_run,
["--project-dir", str(tmpdir), "-t", "compiledb", "-t", "__test"],
)
validate_cliresult(result)

files = _compiledb_files(tmpdir)
assert any(f.endswith("test_add.c") for f in files), files
assert any(f.endswith("calc.c") for f in files), files


def test_compiledb_without_test_target_unchanged(clirunner, validate_cliresult, tmpdir):
# Non-regression: a plain `pio run -t compiledb` must keep its current
# behavior — production sources only, no test sources.
_make_project_with_tests(tmpdir)
result = clirunner.invoke(
cmd_run, ["--project-dir", str(tmpdir), "-t", "compiledb"]
)
validate_cliresult(result)

files = _compiledb_files(tmpdir)
assert any(f.endswith("calc.c") for f in files), files
assert not any(f.endswith("test_add.c") for f in files), files