mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 01:57:13 +02:00
Debug unit tests created with PlatformIO Unit Testing solution // Resolve #948
This commit is contained in:
@ -14,7 +14,8 @@ PlatformIO Core 5
|
|||||||
* **PlatformIO Debugging**
|
* **PlatformIO Debugging**
|
||||||
|
|
||||||
- Boosted `PlatformIO Debugging <https://docs.platformio.org/page/plus/debugging.html>`__ performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack
|
- Boosted `PlatformIO Debugging <https://docs.platformio.org/page/plus/debugging.html>`__ performance thanks to migrating the codebase to the pure Python 3 Asynchronous I/O stack
|
||||||
- Debug native (desktop) application on a host machine (`issue #980 <https://github.com/platformio/platformio-core/issues/980>`_)
|
- `Debug unit tests <https://docs.platformio.org/page/plus/debugging.html#debug-unit-tests>`__ created with `PlatformIO Unit Testing <https://docs.platformio.org/page/plus/unit-testing.html>`__ solution (`issue #948 <https://github.com/platformio/platformio-core/issues/948>`_)
|
||||||
|
- Debug native (desktop) applications on a host machine (`issue #980 <https://github.com/platformio/platformio-core/issues/980>`_)
|
||||||
- Support debugging on Windows using Windows CMD/CLI (`pio debug <https://docs.platformio.org/page/core/userguide/cmd_debug.html>`__) (`issue #3793 <https://github.com/platformio/platformio-core/issues/3793>`_)
|
- Support debugging on Windows using Windows CMD/CLI (`pio debug <https://docs.platformio.org/page/core/userguide/cmd_debug.html>`__) (`issue #3793 <https://github.com/platformio/platformio-core/issues/3793>`_)
|
||||||
- Configure a custom pattern to determine when debugging server is started with a new `debug_server_ready_pattern <https://docs.platformio.org/page/projectconf/section_env_debug.html#debug-server-ready-pattern>`__ option
|
- Configure a custom pattern to determine when debugging server is started with a new `debug_server_ready_pattern <https://docs.platformio.org/page/projectconf/section_env_debug.html#debug-server-ready-pattern>`__ option
|
||||||
- Fixed an issue with silent hanging when a custom debug server is not found (`issue #3756 <https://github.com/platformio/platformio-core/issues/3756>`_)
|
- Fixed an issue with silent hanging when a custom debug server is not found (`issue #3756 <https://github.com/platformio/platformio-core/issues/3756>`_)
|
||||||
|
2
docs
2
docs
Submodule docs updated: b76e3d53bb...b502c2a8dd
@ -210,7 +210,7 @@ env.AddPreAction(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
AlwaysBuild(env.Alias("debug", DEFAULT_TARGETS))
|
AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS))
|
||||||
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))
|
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS))
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
@ -50,7 +50,7 @@ def GetBuildType(env):
|
|||||||
return (
|
return (
|
||||||
"debug"
|
"debug"
|
||||||
if (
|
if (
|
||||||
set(["debug", "sizedata"]) & set(COMMAND_LINE_TARGETS)
|
set(["__debug", "sizedata"]) & set(COMMAND_LINE_TARGETS)
|
||||||
or env.GetProjectOption("build_type") == "debug"
|
or env.GetProjectOption("build_type") == "debug"
|
||||||
)
|
)
|
||||||
else "release"
|
else "release"
|
||||||
|
@ -76,7 +76,9 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro
|
|||||||
env_name = environment or helpers.get_default_debug_env(project_config)
|
env_name = environment or helpers.get_default_debug_env(project_config)
|
||||||
|
|
||||||
if not interface:
|
if not interface:
|
||||||
return helpers.predebug_project(ctx, project_dir, env_name, False, verbose)
|
return helpers.predebug_project(
|
||||||
|
ctx, project_dir, project_config, env_name, False, verbose
|
||||||
|
)
|
||||||
|
|
||||||
env_options = project_config.items(env=env_name, as_dict=True)
|
env_options = project_config.items(env=env_name, as_dict=True)
|
||||||
if "platform" not in env_options:
|
if "platform" not in env_options:
|
||||||
@ -138,11 +140,15 @@ def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unpro
|
|||||||
)
|
)
|
||||||
stream = helpers.GDBMIConsoleStream()
|
stream = helpers.GDBMIConsoleStream()
|
||||||
with proc.capture_std_streams(stream):
|
with proc.capture_std_streams(stream):
|
||||||
helpers.predebug_project(ctx, project_dir, env_name, preload, verbose)
|
helpers.predebug_project(
|
||||||
|
ctx, project_dir, project_config, env_name, preload, verbose
|
||||||
|
)
|
||||||
stream.close()
|
stream.close()
|
||||||
else:
|
else:
|
||||||
click.echo("Preparing firmware for debugging...")
|
click.echo("Preparing firmware for debugging...")
|
||||||
helpers.predebug_project(ctx, project_dir, env_name, preload, verbose)
|
helpers.predebug_project(
|
||||||
|
ctx, project_dir, project_config, env_name, preload, verbose
|
||||||
|
)
|
||||||
|
|
||||||
# save SHA sum of newly created prog
|
# save SHA sum of newly created prog
|
||||||
if load_mode == "modified":
|
if load_mode == "modified":
|
||||||
|
@ -14,9 +14,8 @@
|
|||||||
|
|
||||||
# pylint: disable=too-many-arguments, too-many-locals, too-many-branches
|
# pylint: disable=too-many-arguments, too-many-locals, too-many-branches
|
||||||
|
|
||||||
from fnmatch import fnmatch
|
import fnmatch
|
||||||
from os import getcwd, listdir
|
import os
|
||||||
from os.path import isdir, join
|
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@ -24,6 +23,7 @@ from tabulate import tabulate
|
|||||||
|
|
||||||
from platformio import app, exception, fs, util
|
from platformio import app, exception, fs, util
|
||||||
from platformio.commands.test.embedded import EmbeddedTestProcessor
|
from platformio.commands.test.embedded import EmbeddedTestProcessor
|
||||||
|
from platformio.commands.test.helpers import get_test_names
|
||||||
from platformio.commands.test.native import NativeTestProcessor
|
from platformio.commands.test.native import NativeTestProcessor
|
||||||
from platformio.platform.factory import PlatformFactory
|
from platformio.platform.factory import PlatformFactory
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
@ -50,7 +50,7 @@ from platformio.project.config import ProjectConfig
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-d",
|
"-d",
|
||||||
"--project-dir",
|
"--project-dir",
|
||||||
default=getcwd,
|
default=os.getcwd,
|
||||||
type=click.Path(
|
type=click.Path(
|
||||||
exists=True, file_okay=False, dir_okay=True, writable=True, resolve_path=True
|
exists=True, file_okay=False, dir_okay=True, writable=True, resolve_path=True
|
||||||
),
|
),
|
||||||
@ -102,11 +102,7 @@ def cli( # pylint: disable=redefined-builtin
|
|||||||
with fs.cd(project_dir):
|
with fs.cd(project_dir):
|
||||||
config = ProjectConfig.get_instance(project_conf)
|
config = ProjectConfig.get_instance(project_conf)
|
||||||
config.validate(envs=environment)
|
config.validate(envs=environment)
|
||||||
|
test_names = get_test_names(config)
|
||||||
test_dir = config.get_optional_dir("test")
|
|
||||||
if not isdir(test_dir):
|
|
||||||
raise exception.TestDirNotExists(test_dir)
|
|
||||||
test_names = get_test_names(test_dir)
|
|
||||||
|
|
||||||
if not verbose:
|
if not verbose:
|
||||||
click.echo("Verbose mode can be enabled via `-v, --verbose` option")
|
click.echo("Verbose mode can be enabled via `-v, --verbose` option")
|
||||||
@ -129,9 +125,11 @@ def cli( # pylint: disable=redefined-builtin
|
|||||||
not environment and default_envs and envname not in default_envs,
|
not environment and default_envs and envname not in default_envs,
|
||||||
testname != "*"
|
testname != "*"
|
||||||
and patterns["filter"]
|
and patterns["filter"]
|
||||||
and not any(fnmatch(testname, p) for p in patterns["filter"]),
|
and not any(
|
||||||
|
fnmatch.fnmatch(testname, p) for p in patterns["filter"]
|
||||||
|
),
|
||||||
testname != "*"
|
testname != "*"
|
||||||
and any(fnmatch(testname, p) for p in patterns["ignore"]),
|
and any(fnmatch.fnmatch(testname, p) for p in patterns["ignore"]),
|
||||||
]
|
]
|
||||||
if any(skip_conditions):
|
if any(skip_conditions):
|
||||||
results.append({"env": envname, "test": testname})
|
results.append({"env": envname, "test": testname})
|
||||||
@ -142,7 +140,10 @@ def cli( # pylint: disable=redefined-builtin
|
|||||||
|
|
||||||
cls = (
|
cls = (
|
||||||
EmbeddedTestProcessor
|
EmbeddedTestProcessor
|
||||||
if is_embedded_platform(config.get(section, "platform"))
|
if config.get(section, "platform")
|
||||||
|
and PlatformFactory.new(
|
||||||
|
config.get(section, "platform")
|
||||||
|
).is_embedded()
|
||||||
else NativeTestProcessor
|
else NativeTestProcessor
|
||||||
)
|
)
|
||||||
tp = cls(
|
tp = cls(
|
||||||
@ -185,22 +186,6 @@ def cli( # pylint: disable=redefined-builtin
|
|||||||
raise exception.ReturnErrorCode(1)
|
raise exception.ReturnErrorCode(1)
|
||||||
|
|
||||||
|
|
||||||
def get_test_names(test_dir):
|
|
||||||
names = []
|
|
||||||
for item in sorted(listdir(test_dir)):
|
|
||||||
if isdir(join(test_dir, item)):
|
|
||||||
names.append(item)
|
|
||||||
if not names:
|
|
||||||
names = ["*"]
|
|
||||||
return names
|
|
||||||
|
|
||||||
|
|
||||||
def is_embedded_platform(name):
|
|
||||||
if not name:
|
|
||||||
return False
|
|
||||||
return PlatformFactory.new(name).is_embedded()
|
|
||||||
|
|
||||||
|
|
||||||
def print_processing_header(test, env):
|
def print_processing_header(test, env):
|
||||||
click.echo(
|
click.echo(
|
||||||
"Processing %s in %s environment"
|
"Processing %s in %s environment"
|
||||||
|
30
platformio/commands/test/helpers.py
Normal file
30
platformio/commands/test/helpers.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 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 os
|
||||||
|
|
||||||
|
from platformio import exception
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_names(config):
|
||||||
|
test_dir = config.get_optional_dir("test")
|
||||||
|
if not os.path.isdir(test_dir):
|
||||||
|
raise exception.TestDirNotExists(test_dir)
|
||||||
|
names = []
|
||||||
|
for item in sorted(os.listdir(test_dir)):
|
||||||
|
if os.path.isdir(os.path.join(test_dir, item)):
|
||||||
|
names.append(item)
|
||||||
|
if not names:
|
||||||
|
names = ["*"]
|
||||||
|
return names
|
@ -139,9 +139,9 @@ class TestProcessorBase(object):
|
|||||||
cmd_run,
|
cmd_run,
|
||||||
project_dir=self.options["project_dir"],
|
project_dir=self.options["project_dir"],
|
||||||
project_conf=self.options["project_config"].path,
|
project_conf=self.options["project_config"].path,
|
||||||
upload_port=self.options["upload_port"],
|
upload_port=self.options.get("upload_port"),
|
||||||
verbose=self.options["verbose"],
|
verbose=self.options["verbose"],
|
||||||
silent=self.options["silent"],
|
silent=self.options.get("silent"),
|
||||||
environment=[self.env_name],
|
environment=[self.env_name],
|
||||||
disable_auto_clean="nobuild" in target,
|
disable_auto_clean="nobuild" in target,
|
||||||
target=target,
|
target=target,
|
||||||
|
@ -23,6 +23,9 @@ from os.path import isfile
|
|||||||
from platformio import util
|
from platformio import util
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.commands import PlatformioCLI
|
||||||
from platformio.commands.run.command import cli as cmd_run
|
from platformio.commands.run.command import cli as cmd_run
|
||||||
|
from platformio.commands.run.command import print_processing_header
|
||||||
|
from platformio.commands.test.helpers import get_test_names
|
||||||
|
from platformio.commands.test.processor import TestProcessorBase
|
||||||
from platformio.compat import IS_WINDOWS, is_bytes
|
from platformio.compat import IS_WINDOWS, is_bytes
|
||||||
from platformio.debug.exception import DebugInvalidOptionsError
|
from platformio.debug.exception import DebugInvalidOptionsError
|
||||||
|
|
||||||
@ -72,14 +75,41 @@ def get_default_debug_env(config):
|
|||||||
return default_envs[0] if default_envs else all_envs[0]
|
return default_envs[0] if default_envs else all_envs[0]
|
||||||
|
|
||||||
|
|
||||||
def predebug_project(ctx, project_dir, env_name, preload, verbose):
|
def predebug_project(
|
||||||
ctx.invoke(
|
ctx, project_dir, project_config, env_name, preload, verbose
|
||||||
cmd_run,
|
): # pylint: disable=too-many-arguments
|
||||||
project_dir=project_dir,
|
debug_testname = project_config.get("env:" + env_name, "debug_test")
|
||||||
environment=[env_name],
|
if debug_testname:
|
||||||
target=["debug"] + (["upload"] if preload else []),
|
test_names = get_test_names(project_config)
|
||||||
verbose=verbose,
|
if debug_testname not in test_names:
|
||||||
)
|
raise DebugInvalidOptionsError(
|
||||||
|
"Unknown test name `%s`. Valid names are `%s`"
|
||||||
|
% (debug_testname, ", ".join(test_names))
|
||||||
|
)
|
||||||
|
print_processing_header(env_name, project_config, verbose)
|
||||||
|
tp = TestProcessorBase(
|
||||||
|
ctx,
|
||||||
|
debug_testname,
|
||||||
|
env_name,
|
||||||
|
dict(
|
||||||
|
project_config=project_config,
|
||||||
|
project_dir=project_dir,
|
||||||
|
without_building=False,
|
||||||
|
without_uploading=True,
|
||||||
|
without_testing=True,
|
||||||
|
verbose=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
tp.build_or_upload(["__debug", "__test"] + (["upload"] if preload else []))
|
||||||
|
else:
|
||||||
|
ctx.invoke(
|
||||||
|
cmd_run,
|
||||||
|
project_dir=project_dir,
|
||||||
|
environment=[env_name],
|
||||||
|
target=["__debug"] + (["upload"] if preload else []),
|
||||||
|
verbose=verbose,
|
||||||
|
)
|
||||||
|
|
||||||
if preload:
|
if preload:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
|
@ -703,6 +703,11 @@ ProjectOptions = OrderedDict(
|
|||||||
"for an incoming connection"
|
"for an incoming connection"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ConfigEnvOption(
|
||||||
|
group="debug",
|
||||||
|
name="debug_test",
|
||||||
|
description=("A name of a unit test to be debugged"),
|
||||||
|
),
|
||||||
# Advanced
|
# Advanced
|
||||||
ConfigEnvOption(
|
ConfigEnvOption(
|
||||||
group="advanced",
|
group="advanced",
|
||||||
|
Reference in New Issue
Block a user