diff --git a/README.rst b/README.rst index 3a4f42bd..6e5b2736 100644 --- a/README.rst +++ b/README.rst @@ -156,9 +156,12 @@ Then, run the test suite locally from the top level directory:: # Recommended in an active virtual environment poe all - # Manually + # Manually (test the installed west version) pytest + # Manually (test the local copy) + pytest -o pythonpath=src + The ``all`` target from ``poe`` runs multiple tasks sequentially. Run ``poe -h`` to get the list of configured tasks. You can pass arguments to the task running ``poe``. This is especially useful diff --git a/pyproject.toml b/pyproject.toml index be1b4f90..54d1599e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,8 +76,8 @@ omit = [ [tool.coverage.report] omit = [ "*/tmp/*", - "net-tools/scripts/test.py", - "subdir/Kconfiglib/scripts/test.py", + "*/net-tools/scripts/test.py", + "*/subdir/Kconfiglib/scripts/test.py", ] [tool.coverage.paths] diff --git a/src/west/app/main.py b/src/west/app/main.py index ddbe3eea..0ddec854 100755 --- a/src/west/app/main.py +++ b/src/west/app/main.py @@ -30,6 +30,13 @@ import colorama +if __name__ == "__main__": + # Prepend the west src directory to sys.path so that running this script + # directly in a local tree always uses the according local 'west' modules + # instead of any installed modules. + src_dir = Path(__file__).resolve().parents[2] + sys.path.insert(0, os.fspath(src_dir)) + import west.configuration from west import log from west.app.config import Config diff --git a/tests/conftest.py b/tests/conftest.py index 114d4d7f..d67445af 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 import contextlib +import io import os import platform import shutil @@ -14,6 +15,8 @@ import pytest +from west.app import main + GIT = shutil.which('git') # Git capabilities are discovered at runtime in @@ -366,48 +369,74 @@ def check_output(*args, **kwargs): return out_bytes.decode(sys.getdefaultencoding()) -def cmd(cmd, cwd=None, stderr=None, env=None): - # Run a west command in a directory (cwd defaults to os.getcwd()). - # - # This helper takes the command as a string. - # - # This helper relies on the test environment to ensure that the - # 'west' executable is a bootstrapper installed from the current - # west source code. - # - # stdout from cmd is captured and returned. The command is run in - # a python subprocess so that program-level setup and teardown - # happen fresh. - - # If you have quoting issues: do NOT quote. It's not portable. - # Instead, pass `cmd` as a list. - cmd = ['west'] + (cmd.split() if isinstance(cmd, str) else cmd) - - print('running:', cmd) - if env: - print('with non-default environment:') - for k in env: - if k not in os.environ or env[k] != os.environ[k]: - print(f'\t{k}={env[k]}') - for k in os.environ: - if k not in env: - print(f'\t{k}: deleted, was: {os.environ[k]}') - if cwd is not None: - cwd = os.fspath(cwd) - print(f'in {cwd}') - try: - return check_output(cmd, cwd=cwd, stderr=stderr, env=env) - except subprocess.CalledProcessError: - print('cmd: west:', shutil.which('west'), file=sys.stderr) - raise - - -def cmd_raises(cmd_str_or_list, expected_exception_type, cwd=None, env=None): - # Similar to 'cmd' but an expected exception is caught. - # Returns the output together with stderr data - with pytest.raises(expected_exception_type) as exc_info: - cmd(cmd_str_or_list, stderr=subprocess.STDOUT, cwd=cwd, env=env) - return exc_info.value.output.decode("utf-8") +def _cmd(cmd, cwd=None, env=None): + # Executes a west command by invoking the `main()` function with the + # provided command arguments. + # Parameters: + # cwd: The working directory in which to execute the command. + # env: A dictionary of extra environment variables to apply temporarily + # during execution. + + # ensure that cmd is a list of strings + cmd = cmd.split() if isinstance(cmd, str) else cmd + cmd = [str(c) for c in cmd] + + # run main() + with ( + chdir(cwd or Path.cwd()), + update_env(env or {}), + ): + try: + main.main(cmd) + except SystemExit as e: + if e.code: + raise e + except Exception as e: + print(f'Uncaught exception type {e}', file=sys.stderr) + raise e + + +def cmd(cmd: list | str, cwd=None, stderr: io.StringIO | None = None, env=None): + # Same as _cmd(), but it captures and returns combined stdout and stderr. + # Optionally stderr can be captured separately into given stderr. + # Note that this function does not capture any stdout or stderr from an + # internally invoked subprocess. + stdout_buf = io.StringIO() + stderr_buf = stderr or stdout_buf + with contextlib.redirect_stdout(stdout_buf), contextlib.redirect_stderr(stderr_buf): + _cmd(cmd, cwd, env) + return stdout_buf.getvalue() + + +def cmd_raises(cmd: list | str, expected_exception_type, stdout=None, cwd=None, env=None): + # Similar to '_cmd' but an expected exception is caught. + # The exception is returned together with stderr. + # Optionally stdout is captured into given stdout (io.StringIO) + stdout_buf = stdout or sys.stdout + stderr_buf = io.StringIO() + with ( + contextlib.redirect_stdout(stdout_buf), + contextlib.redirect_stderr(stderr_buf), + pytest.raises(expected_exception_type) as exc_info, + ): + _cmd(cmd, cwd=cwd, env=env) + return exc_info, stderr_buf.getvalue() + + +def cmd_subprocess(cmd: list | str, *args, **kwargs): + # This function behaves similarly to `cmd()`, but executes the command in a + # separate Python subprocess, capturing all stdout output. + # The captured stdout includes both Python-level output and the output of + # any subprocesses spawned internally. This makes the function particularly + # useful in test cases where the code under test launches subprocesses and + # the combined stdout needs to be verified. + # The main drawback is that it cannot be debugged within Python, so it + # should only be used sparingly in tests. + cmd = cmd if isinstance(cmd, list) else cmd.split() + cmd = [sys.executable, main.__file__] + cmd + print('running (subprocess):', cmd) + ret = check_output(cmd, *args, **kwargs) + return ret def create_workspace(workspace_dir, and_git=True): diff --git a/tests/test_alias.py b/tests/test_alias.py index eb6bd9a6..36335ea6 100644 --- a/tests/test_alias.py +++ b/tests/test_alias.py @@ -2,10 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 -import subprocess - import pytest -from conftest import cmd +from conftest import cmd, cmd_raises @pytest.fixture(autouse=True) @@ -50,10 +48,8 @@ def test_alias_infinite_recursion(): cmd('config alias.test2 test3') cmd('config alias.test3 test1') - with pytest.raises(subprocess.CalledProcessError) as excinfo: - cmd('test1', stderr=subprocess.STDOUT) - - assert 'unknown command "test1";' in str(excinfo.value.stdout) + exc, _ = cmd_raises('test1', SystemExit) + assert 'unknown command "test1";' in str(exc.value) def test_alias_empty(): @@ -62,10 +58,8 @@ def test_alias_empty(): # help command shouldn't fail cmd('help') - with pytest.raises(subprocess.CalledProcessError) as excinfo: - cmd('empty', stderr=subprocess.STDOUT) - - assert 'empty alias "empty"' in str(excinfo.value.stdout) + exc, _ = cmd_raises('empty', SystemExit) + assert 'empty alias "empty"' in str(exc.value) def test_alias_early_args(): diff --git a/tests/test_config.py b/tests/test_config.py index f3ab679f..79b8bef4 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -5,7 +5,6 @@ import configparser import os import pathlib -import subprocess import textwrap from typing import Any @@ -351,13 +350,13 @@ def test_append(): def test_append_novalue(): - err_msg = cmd_raises('config -a pytest.foo', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -a pytest.foo', SystemExit) assert '-a requires both name and value' in err_msg def test_append_notfound(): update_testcfg('pytest', 'key', 'val', configfile=LOCAL) - err_msg = cmd_raises('config -a pytest.foo bar', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -a pytest.foo bar', SystemExit) assert 'option pytest.foo not found in the local configuration file' in err_msg @@ -497,7 +496,7 @@ def test_delete_cmd_all(): assert cfg(f=ALL)['pytest']['key'] == 'local' cmd('config -D pytest.key') assert 'pytest' not in cfg(f=ALL) - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('config -D pytest.key') @@ -511,7 +510,7 @@ def test_delete_cmd_none(): assert cmd('config pytest.key').rstrip() == 'global' cmd('config -d pytest.key') assert cmd('config pytest.key').rstrip() == 'system' - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('config -d pytest.key') @@ -521,7 +520,7 @@ def test_delete_cmd_system(): cmd('config --global pytest.key global') cmd('config --local pytest.key local') cmd('config -d --system pytest.key') - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('config --system pytest.key') assert cmd('config --global pytest.key').rstrip() == 'global' assert cmd('config --local pytest.key').rstrip() == 'local' @@ -534,7 +533,7 @@ def test_delete_cmd_global(): cmd('config --local pytest.key local') cmd('config -d --global pytest.key') assert cmd('config --system pytest.key').rstrip() == 'system' - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('config --global pytest.key') assert cmd('config --local pytest.key').rstrip() == 'local' @@ -547,17 +546,17 @@ def test_delete_cmd_local(): cmd('config -d --local pytest.key') assert cmd('config --system pytest.key').rstrip() == 'system' assert cmd('config --global pytest.key').rstrip() == 'global' - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('config --local pytest.key') def test_delete_cmd_error(): # Verify illegal combinations of flags error out. - err_msg = cmd_raises('config -l -d pytest.key', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -l -d pytest.key', SystemExit) assert 'argument -d/--delete: not allowed with argument -l/--list' in err_msg - err_msg = cmd_raises('config -l -D pytest.key', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -l -D pytest.key', SystemExit) assert 'argument -D/--delete-all: not allowed with argument -l/--list' in err_msg - err_msg = cmd_raises('config -d -D pytest.key', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -d -D pytest.key', SystemExit) assert 'argument -D/--delete-all: not allowed with argument -d/--delete' in err_msg @@ -591,19 +590,19 @@ def test_config_precedence(): def test_config_missing_key(): - err_msg = cmd_raises('config pytest', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config pytest', SystemExit) assert 'invalid configuration option "pytest"; expected "section.key" format' in err_msg def test_unset_config(): # Getting unset configuration options should raise an error. # With verbose output, the exact missing option should be printed. - err_msg = cmd_raises('-v config pytest.missing', subprocess.CalledProcessError) + _, err_msg = cmd_raises('-v config pytest.missing', SystemExit) assert 'pytest.missing is unset' in err_msg def test_no_args(): - err_msg = cmd_raises('config', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config', SystemExit) assert 'missing argument name' in err_msg @@ -611,7 +610,7 @@ def test_list(): def sorted_list(other_args=''): return list(sorted(cmd('config -l ' + other_args).splitlines())) - err_msg = cmd_raises('config -l pytest.foo', subprocess.CalledProcessError) + _, err_msg = cmd_raises('config -l pytest.foo', SystemExit) assert '-l cannot be combined with name argument' in err_msg assert cmd('config -l').strip() == '' diff --git a/tests/test_help.py b/tests/test_help.py index 530b9584..d9ab299b 100644 --- a/tests/test_help.py +++ b/tests/test_help.py @@ -1,8 +1,6 @@ # Copyright (c) 2020, Nordic Semiconductor ASA import itertools -import os -import sys from conftest import cmd @@ -33,13 +31,6 @@ def test_extension_help_and_dash_h(west_init_tmpdir): ext2out = cmd('test-extension -h') expected = EXTENSION_EXPECTED - if sys.platform == 'win32': - # Manage gratuitous incompatibilities: - # - # - multiline python strings are \n separated even on windows - # - the windows command help output gets an extra newline - expected = [os.linesep.join(case.splitlines()) + os.linesep for case in EXTENSION_EXPECTED] - assert ext1out == ext2out assert ext1out in expected diff --git a/tests/test_main.py b/tests/test_main.py index ef96e8ad..41fc886c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,5 +1,9 @@ -import subprocess +import runpy import sys +from pathlib import Path + +import pytest +from conftest import cmd, cmd_subprocess import west.version @@ -11,7 +15,36 @@ def test_main(): # sane (i.e. the actual version number is printed instead of # simply an error message to stderr). - output_as_module = subprocess.check_output([sys.executable, '-m', 'west', '--version']).decode() - output_directly = subprocess.check_output(['west', '--version']).decode() - assert west.version.__version__ in output_as_module - assert output_as_module == output_directly + expected_version = west.version.__version__ + + # call west executable directly + output_directly = cmd(['--version']) + assert expected_version in output_directly + + output_subprocess = cmd_subprocess('--version') + assert expected_version in output_subprocess + + # output must be same in both cases + assert output_subprocess.rstrip() == output_directly.rstrip() + + +def test_module_run(tmp_path, monkeypatch): + actual_path = ['initial-path'] + + # mock sys.argv and sys.path + monkeypatch.setattr(sys, 'path', actual_path) + monkeypatch.setattr(sys, 'argv', ['west', '--version']) + + # ensure that west.app.main is freshly loaded + sys.modules.pop('west.app.main', None) + + # run west.app.main as module + with pytest.raises(SystemExit) as exit_info: + runpy.run_module('west.app.main', run_name='__main__') + + # check that exit code is 0 + assert exit_info.value.code == 0 + + # check that that the sys.path was correctly inserted + expected_path = Path(__file__).parents[1] / 'src' + assert actual_path == [f'{expected_path}', 'initial-path'] diff --git a/tests/test_project.py b/tests/test_project.py index c929fab6..58c3906a 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -10,6 +10,7 @@ from pathlib import Path, PurePath import pytest +import yaml from conftest import ( GIT, WINDOWS, @@ -19,6 +20,7 @@ check_proj_consistency, cmd, cmd_raises, + cmd_subprocess, create_branch, create_repo, create_workspace, @@ -148,10 +150,10 @@ def test_list(west_update_tmpdir): abs_inside = cmd(_list_f('{name}') + [klib_abs], cwd=klib_abs).strip() assert abs_inside == 'Kconfiglib' - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('list NOT_A_PROJECT', cwd=klib_abs) - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('list NOT_A_PROJECT') @@ -235,7 +237,7 @@ def check(command_string, expected): ['foo .foo-group-1,foo-group-2. foo inactive', 'bar .. path-for-bar active'], ) - err_msg = cmd_raises('list -i foo bar', subprocess.CalledProcessError) + _, err_msg = cmd_raises('list -i foo bar', SystemExit) assert '-i cannot be combined with an explicit project list' in err_msg cmd('config manifest.group-filter +foo-group-1') @@ -548,7 +550,7 @@ def test_compare(config_tmpdir, west_init_tmpdir): assert 'foo' in actual # --exit-code should work for the manifest repository too. - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('compare --exit-code') # Remove the file and verify compare output is empty again. @@ -577,7 +579,7 @@ def test_compare(config_tmpdir, west_init_tmpdir): cmd('config -d manifest.group-filter') # Verify --exit-code works as advertised, and clean up again. - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('compare --exit-code') os.unlink(bar) assert cmd('compare --exit-code') == '' @@ -639,7 +641,7 @@ def test_forall(west_init_tmpdir): # 'forall' with no projects cloned shouldn't fail - assert cmd(['forall', '-c', 'echo foo']).splitlines() == [ + assert cmd_subprocess(['forall', '-c', 'echo foo']).splitlines() == [ '=== running "echo foo" in manifest (zephyr):', 'foo', ] @@ -647,7 +649,7 @@ def test_forall(west_init_tmpdir): # Neither should it fail after cloning one or both projects cmd('update net-tools') - assert cmd(['forall', '-c', 'echo foo']).splitlines() == [ + assert cmd_subprocess(['forall', '-c', 'echo foo']).splitlines() == [ '=== running "echo foo" in manifest (zephyr):', 'foo', '=== running "echo foo" in net-tools (net-tools):', @@ -658,7 +660,7 @@ def test_forall(west_init_tmpdir): env_var = "%WEST_PROJECT_NAME%" if WINDOWS else "$WEST_PROJECT_NAME" - assert cmd(['forall', '-c', f'echo {env_var}']).splitlines() == [ + assert cmd_subprocess(['forall', '-c', f'echo {env_var}']).splitlines() == [ f'=== running "echo {env_var}" in manifest (zephyr):', 'manifest', f'=== running "echo {env_var}" in net-tools (net-tools):', @@ -666,7 +668,7 @@ def test_forall(west_init_tmpdir): ] cmd('update Kconfiglib') - assert cmd(['forall', '-c', 'echo foo']).splitlines() == [ + assert cmd_subprocess(['forall', '-c', 'echo foo']).splitlines() == [ '=== running "echo foo" in manifest (zephyr):', 'foo', '=== running "echo foo" in Kconfiglib (subdir/Kconfiglib):', @@ -675,12 +677,45 @@ def test_forall(west_init_tmpdir): 'foo', ] - assert cmd('forall --group Kconfiglib-group -c'.split() + ['echo foo']).splitlines() == [ + assert cmd_subprocess( + 'forall --group Kconfiglib-group -c'.split() + ['echo foo'] + ).splitlines() == [ '=== running "echo foo" in Kconfiglib (subdir/Kconfiglib):', 'foo', ] +TEST_CASES_FORALL_ENV_VARS = [ + # (env_var, expected_zephyr, expected_net_tools) + ('WEST_PROJECT_NAME', 'manifest', 'net-tools'), + ('WEST_PROJECT_PATH', 'zephyr', 'net-tools'), + ('WEST_PROJECT_ABSPATH', 'zephyr', 'net-tools'), + ('WEST_PROJECT_REVISION', 'HEAD', 'master'), +] + + +@pytest.mark.parametrize("test_case", TEST_CASES_FORALL_ENV_VARS) +def test_forall_env_vars(west_init_tmpdir, test_case): + west_init_tmpdir = Path(west_init_tmpdir) + cmd('update net-tools') + env_var, expected_zephyr, expected_net_tools = test_case + # convert expected to absolute path + if env_var == 'WEST_PROJECT_ABSPATH': + expected_zephyr = west_init_tmpdir / expected_zephyr + expected_net_tools = west_init_tmpdir / expected_net_tools + + # Windows vs. Linux + env_var = f'%{env_var}%' if WINDOWS else f'${env_var}' + + stdout = cmd_subprocess(['forall', '-c', f'echo {env_var}']) + assert stdout.splitlines() == [ + f'=== running "echo {env_var}" in manifest (zephyr):', + f'{expected_zephyr}', + f'=== running "echo {env_var}" in net-tools (net-tools):', + f'{expected_net_tools}', + ] + + def test_grep(west_init_tmpdir): # Make sure we don't find things we don't expect, and do find # things we do. @@ -939,13 +974,13 @@ def test_update_some_with_imports(repos_tmpdir): # Updating unknown projects should fail as always. - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('update unknown-project', cwd=ws) # Updating a list of projects when some are resolved via project # imports must fail. - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('update Kconfiglib net-tools', cwd=ws) # Updates of projects defined in the manifest repository or all @@ -1642,7 +1677,7 @@ def test_update_recovery(tmpdir): # Use west init -l + west update to point p's manifest-rev at rbad. cmd(['init', '-l', m], cwd=workspacestr) - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('update', cwd=workspacestr) # Make sure p's manifest-rev points to the bad revision as expected. @@ -1745,33 +1780,24 @@ def test_init_again(west_init_tmpdir): # Test that 'west init' on an initialized tmpdir errors out # with a message that indicates it's already initialized. - popen = subprocess.Popen( - 'west init'.split(), stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, cwd=west_init_tmpdir - ) - _, stderr = popen.communicate() - assert popen.returncode - assert b'already initialized' in stderr - - popen = subprocess.Popen( - 'west init -m http://example.com'.split(), - stdout=subprocess.DEVNULL, - stderr=subprocess.PIPE, - cwd=west_init_tmpdir, - ) - _, stderr = popen.communicate() - assert popen.returncode - assert b'already initialized' in stderr + expected_msg = f'FATAL ERROR: already initialized in {west_init_tmpdir}' + + exc, stderr = cmd_raises('init', SystemExit, cwd=west_init_tmpdir) + assert exc.value.code == 1 + assert expected_msg in stderr + + exc, stderr = cmd_raises('init -m http://example.com', SystemExit, cwd=west_init_tmpdir) + assert exc.value.code == 1 + assert expected_msg in stderr manifest = west_init_tmpdir / '..' / 'repos' / 'zephyr' - popen = subprocess.Popen( - ['west', '-vvv', 'init', '-m', str(manifest), 'workspace'], - stdout=subprocess.DEVNULL, - stderr=subprocess.PIPE, - cwd=west_init_tmpdir.dirname, + exc, stderr = cmd_raises( + f'-vvv init -m {manifest} workspace', RuntimeError, cwd=west_init_tmpdir.dirname ) - _, stderr = popen.communicate() - assert popen.returncode - assert b'already initialized' in stderr + assert expected_msg in stderr + + expected_msg = "die with -vvv or more shows a stack trace. exit_code argument is ignored" + assert expected_msg in str(exc.value) def test_init_local_manifest_project(repos_tmpdir): @@ -1810,7 +1836,7 @@ def test_init_local_manifest_project(repos_tmpdir): def test_init_local_already_initialized_failure(west_init_tmpdir): # Test that 'west init -l' on an initialized tmpdir errors out - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd(f'init -l "{west_init_tmpdir}"') @@ -1822,7 +1848,7 @@ def test_init_local_missing_west_yml_failure(repos_tmpdir): clone(str(repos_tmpdir.join('repos', 'zephyr')), str(zephyr_install_dir)) os.remove(str(zephyr_install_dir.join('west.yml'))) - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd(f'init -l "{zephyr_install_dir}"') @@ -1838,7 +1864,7 @@ def test_init_local_with_manifest_filename(repos_tmpdir): os.rename(str(zephyr_install_dir / 'west.yml'), str(zephyr_install_dir / 'project.yml')) # fails because west.yml is missing - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd(['init', '-l', zephyr_install_dir]) # create a manifest with a syntax error so we can test if it's being parsed @@ -1850,7 +1876,7 @@ def test_init_local_with_manifest_filename(repos_tmpdir): # init with a local manifest doesn't parse the file, so let's access it workspace.chdir() - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(yaml.parser.ParserError): cmd('list') os.chdir(cwd) @@ -1880,7 +1906,7 @@ def test_init_local_with_clone_option_failure(repos_tmpdir): west_tmpdir = repos_tmpdir / 'workspace' - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd(['init', '-l', '-o=--depth=1', west_tmpdir]) @@ -2051,7 +2077,7 @@ def test_init_with_manifest_filename(repos_tmpdir): ) # syntax error - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(yaml.parser.ParserError): cmd(['init', '-m', manifest, west_tmpdir]) shutil.move(west_tmpdir, repos_tmpdir / 'workspace-syntaxerror') @@ -2085,7 +2111,7 @@ def test_init_with_manifest_in_subdir(repos_tmpdir): def test_extension_command_execution(west_init_tmpdir): - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('test-extension') cmd('update') @@ -2279,11 +2305,11 @@ def do_run(self, args, ignored): ] # Expect output from the built-in command, not its Kconfiglib duplicate. - actual = cmd('list zephyr -f {name}', stderr=subprocess.STDOUT).splitlines() + actual = cmd('list zephyr -f {name}').splitlines() assert actual == expected_warns + ['manifest'] # Expect output from the Kconfiglib command, not its net-tools duplicate. - actual = cmd('test-extension', stderr=subprocess.STDOUT).splitlines() + actual = cmd('test-extension').splitlines() assert actual == expected_warns + ['Testing kconfig test command'] @@ -2291,7 +2317,7 @@ def test_topdir_none(tmpdir): # Running west topdir outside of any workspace ought to fail. tmpdir.chdir() - with pytest.raises(subprocess.CalledProcessError): + with pytest.raises(SystemExit): cmd('topdir') @@ -2372,7 +2398,7 @@ def update_helper(west_tmpdir, updater=default_updater): def output_or_none(*args, **kwargs): try: ret = check_output(*args, **kwargs) - except (FileNotFoundError, NotADirectoryError, subprocess.CalledProcessError): + except (FileNotFoundError, NotADirectoryError, SystemExit): ret = None return ret