diff options
Diffstat (limited to 'tests/languages')
-rw-r--r-- | tests/languages/conda_test.py | 36 | ||||
-rw-r--r-- | tests/languages/coursier_test.py | 45 | ||||
-rw-r--r-- | tests/languages/dart_test.py | 62 | ||||
-rw-r--r-- | tests/languages/golang_test.py | 57 | ||||
-rw-r--r-- | tests/languages/helpers_test.py | 28 | ||||
-rw-r--r-- | tests/languages/lua_test.py | 58 | ||||
-rw-r--r-- | tests/languages/perl_test.py | 69 | ||||
-rw-r--r-- | tests/languages/r_test.py | 263 | ||||
-rw-r--r-- | tests/languages/ruby_test.py | 4 | ||||
-rw-r--r-- | tests/languages/rust_test.py | 7 | ||||
-rw-r--r-- | tests/languages/swift_test.py | 31 |
11 files changed, 530 insertions, 130 deletions
diff --git a/tests/languages/conda_test.py b/tests/languages/conda_test.py index 5023b2a..83aaebe 100644 --- a/tests/languages/conda_test.py +++ b/tests/languages/conda_test.py @@ -1,9 +1,13 @@ from __future__ import annotations +import os.path + import pytest from pre_commit import envcontext -from pre_commit.languages.conda import _conda_exe +from pre_commit.languages import conda +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language @pytest.mark.parametrize( @@ -37,4 +41,32 @@ from pre_commit.languages.conda import _conda_exe ) def test_conda_exe(ctx, expected): with envcontext.envcontext(ctx): - assert _conda_exe() == expected + assert conda._conda_exe() == expected + + +def test_conda_language(tmp_path): + environment_yml = '''\ +channels: [conda-forge, defaults] +dependencies: [python, pip] +''' + tmp_path.joinpath('environment.yml').write_text(environment_yml) + + ret, out = run_language( + tmp_path, + conda, + 'python -c "import sys; print(sys.prefix)"', + ) + assert ret == 0 + assert os.path.basename(out.strip()) == b'conda-default' + + +def test_conda_additional_deps(tmp_path): + _make_local_repo(tmp_path) + + ret = run_language( + tmp_path, + conda, + 'python -c "import botocore; print(1)"', + deps=('botocore',), + ) + assert ret == (0, b'1\n') diff --git a/tests/languages/coursier_test.py b/tests/languages/coursier_test.py new file mode 100644 index 0000000..dbb746c --- /dev/null +++ b/tests/languages/coursier_test.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import pytest + +from pre_commit.errors import FatalError +from pre_commit.languages import coursier +from testing.language_helpers import run_language + + +def test_coursier_hook(tmp_path): + echo_java_json = '''\ +{ + "repositories": ["central"], + "dependencies": ["io.get-coursier:echo:latest.stable"] +} +''' + + channel_dir = tmp_path.joinpath('.pre-commit-channel') + channel_dir.mkdir() + channel_dir.joinpath('echo-java.json').write_text(echo_java_json) + + ret = run_language( + tmp_path, + coursier, + 'echo-java', + args=('Hello', 'World', 'from', 'coursier'), + ) + assert ret == (0, b'Hello World from coursier\n') + + +def test_coursier_hook_additional_dependencies(tmp_path): + ret = run_language( + tmp_path, + coursier, + 'scalafmt --version', + deps=('scalafmt:3.6.1',), + ) + assert ret == (0, b'scalafmt 3.6.1\n') + + +def test_error_if_no_deps_or_channel(tmp_path): + with pytest.raises(FatalError) as excinfo: + run_language(tmp_path, coursier, 'dne') + msg, = excinfo.value.args + assert msg == 'expected .pre-commit-channel dir or additional_dependencies' diff --git a/tests/languages/dart_test.py b/tests/languages/dart_test.py new file mode 100644 index 0000000..5bb5aa6 --- /dev/null +++ b/tests/languages/dart_test.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import re_assert + +from pre_commit.languages import dart +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language + + +def test_dart(tmp_path): + pubspec_yaml = '''\ +environment: + sdk: '>=2.10.0 <3.0.0' + +name: hello_world_dart + +executables: + hello-world-dart: + +dependencies: + ansicolor: ^2.0.1 +''' + hello_world_dart_dart = '''\ +import 'package:ansicolor/ansicolor.dart'; + +void main() { + AnsiPen pen = new AnsiPen()..red(); + print("hello hello " + pen("world")); +} +''' + tmp_path.joinpath('pubspec.yaml').write_text(pubspec_yaml) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_dir.joinpath('hello-world-dart.dart').write_text(hello_world_dart_dart) + + expected = (0, b'hello hello world\n') + assert run_language(tmp_path, dart, 'hello-world-dart') == expected + + +def test_dart_additional_deps(tmp_path): + _make_local_repo(str(tmp_path)) + + ret = run_language( + tmp_path, + dart, + 'hello-world-dart', + deps=('hello_world_dart',), + ) + assert ret == (0, b'hello hello world\n') + + +def test_dart_additional_deps_versioned(tmp_path): + _make_local_repo(str(tmp_path)) + + ret, out = run_language( + tmp_path, + dart, + 'secure-random -l 4 -b 16', + deps=('encrypt:5.0.0',), + ) + assert ret == 0 + re_assert.Matches('^[a-f0-9]{8}\n$').assert_matches(out.decode()) diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 9e393cb..0219261 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -1,22 +1,43 @@ from __future__ import annotations +import re +from unittest import mock + import pytest -from pre_commit.languages.golang import guess_go_dir - - -@pytest.mark.parametrize( - ('url', 'expected'), - ( - ('/im/a/path/on/disk', 'unknown_src_dir'), - ('file:///im/a/path/on/disk', 'unknown_src_dir'), - ('git@github.com:golang/lint', 'github.com/golang/lint'), - ('git://github.com/golang/lint', 'github.com/golang/lint'), - ('http://github.com/golang/lint', 'github.com/golang/lint'), - ('https://github.com/golang/lint', 'github.com/golang/lint'), - ('ssh://git@github.com/golang/lint', 'github.com/golang/lint'), - ('git@github.com:golang/lint.git', 'github.com/golang/lint'), - ), -) -def test_guess_go_dir(url, expected): - assert guess_go_dir(url) == expected +import pre_commit.constants as C +from pre_commit.languages import golang +from pre_commit.languages import helpers + + +ACTUAL_GET_DEFAULT_VERSION = golang.get_default_version.__wrapped__ + + +@pytest.fixture +def exe_exists_mck(): + with mock.patch.object(helpers, 'exe_exists') as mck: + yield mck + + +def test_golang_default_version_system_available(exe_exists_mck): + exe_exists_mck.return_value = True + assert ACTUAL_GET_DEFAULT_VERSION() == 'system' + + +def test_golang_default_version_system_not_available(exe_exists_mck): + exe_exists_mck.return_value = False + assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT + + +ACTUAL_INFER_GO_VERSION = golang._infer_go_version.__wrapped__ + + +def test_golang_infer_go_version_not_default(): + assert ACTUAL_INFER_GO_VERSION('1.19.4') == '1.19.4' + + +def test_golang_infer_go_version_default(): + version = ACTUAL_INFER_GO_VERSION(C.DEFAULT) + + assert version != C.DEFAULT + assert re.match(r'^\d+\.\d+\.\d+$', version) diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index f333e79..c209e7e 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -12,7 +12,6 @@ from pre_commit import parse_shebang from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from testing.auto_namedtuple import auto_namedtuple @pytest.fixture @@ -94,31 +93,22 @@ def test_assert_no_additional_deps(): ) -SERIAL_FALSE = auto_namedtuple(require_serial=False) -SERIAL_TRUE = auto_namedtuple(require_serial=True) - - def test_target_concurrency_normal(): with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 123 - - -def test_target_concurrency_cpu_count_require_serial_true(): - with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_TRUE) == 1 + assert helpers.target_concurrency() == 123 def test_target_concurrency_testing_env_var(): with mock.patch.dict( os.environ, {'PRE_COMMIT_NO_CONCURRENCY': '1'}, clear=True, ): - assert helpers.target_concurrency(SERIAL_FALSE) == 1 + assert helpers.target_concurrency() == 1 def test_target_concurrency_on_travis(): with mock.patch.dict(os.environ, {'TRAVIS': '1'}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 2 + assert helpers.target_concurrency() == 2 def test_target_concurrency_cpu_count_not_implemented(): @@ -126,10 +116,20 @@ def test_target_concurrency_cpu_count_not_implemented(): multiprocessing, 'cpu_count', side_effect=NotImplementedError, ): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 1 + assert helpers.target_concurrency() == 1 def test_shuffled_is_deterministic(): seq = [str(i) for i in range(10)] expected = ['4', '0', '5', '1', '8', '6', '2', '3', '7', '9'] assert helpers._shuffled(seq) == expected + + +def test_xargs_require_serial_is_not_shuffled(): + ret, out = helpers.run_xargs( + ('echo',), [str(i) for i in range(10)], + require_serial=True, + color=False, + ) + assert ret == 0 + assert out.strip() == b'0 1 2 3 4 5 6 7 8 9' diff --git a/tests/languages/lua_test.py b/tests/languages/lua_test.py new file mode 100644 index 0000000..b2767b7 --- /dev/null +++ b/tests/languages/lua_test.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import sys + +import pytest + +from pre_commit.languages import lua +from pre_commit.util import make_executable +from testing.language_helpers import run_language + +pytestmark = pytest.mark.skipif( + sys.platform == 'win32', + reason='lua is not supported on windows', +) + + +def test_lua(tmp_path): # pragma: win32 no cover + rockspec = '''\ +package = "hello" +version = "dev-1" + +source = { + url = "git+ssh://git@github.com/pre-commit/pre-commit.git" +} +description = {} +dependencies = {} +build = { + type = "builtin", + modules = {}, + install = { + bin = {"bin/hello-world-lua"} + }, +} +''' + hello_world_lua = '''\ +#!/usr/bin/env lua +print('hello world') +''' + tmp_path.joinpath('hello-dev-1.rockspec').write_text(rockspec) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_file = bin_dir.joinpath('hello-world-lua') + bin_file.write_text(hello_world_lua) + make_executable(bin_file) + + expected = (0, b'hello world\n') + assert run_language(tmp_path, lua, 'hello-world-lua') == expected + + +def test_lua_additional_dependencies(tmp_path): # pragma: win32 no cover + ret, out = run_language( + tmp_path, + lua, + 'luacheck --version', + deps=('luacheck',), + ) + assert ret == 0 + assert out.startswith(b'Luacheck: ') diff --git a/tests/languages/perl_test.py b/tests/languages/perl_test.py new file mode 100644 index 0000000..042478d --- /dev/null +++ b/tests/languages/perl_test.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from pre_commit.languages import perl +from pre_commit.store import _make_local_repo +from pre_commit.util import make_executable +from testing.language_helpers import run_language + + +def test_perl_install(tmp_path): + makefile_pl = '''\ +use strict; +use warnings; + +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => "PreCommitHello", + VERSION_FROM => "lib/PreCommitHello.pm", + EXE_FILES => [qw(bin/pre-commit-perl-hello)], +); +''' + bin_perl_hello = '''\ +#!/usr/bin/env perl + +use strict; +use warnings; +use PreCommitHello; + +PreCommitHello::hello(); +''' + lib_hello_pm = '''\ +package PreCommitHello; + +use strict; +use warnings; + +our $VERSION = "0.1.0"; + +sub hello { + print "Hello from perl-commit Perl!\n"; +} + +1; +''' + tmp_path.joinpath('Makefile.PL').write_text(makefile_pl) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + exe = bin_dir.joinpath('pre-commit-perl-hello') + exe.write_text(bin_perl_hello) + make_executable(exe) + lib_dir = tmp_path.joinpath('lib') + lib_dir.mkdir() + lib_dir.joinpath('PreCommitHello.pm').write_text(lib_hello_pm) + + ret = run_language(tmp_path, perl, 'pre-commit-perl-hello') + assert ret == (0, b'Hello from perl-commit Perl!\n') + + +def test_perl_additional_dependencies(tmp_path): + _make_local_repo(str(tmp_path)) + + ret, out = run_language( + tmp_path, + perl, + 'perltidy --version', + deps=('SHANCOCK/Perl-Tidy-20211029.tar.gz',), + ) + assert ret == 0 + assert out.startswith(b'This is perltidy, v20211029') diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index c52d5ac..02c559c 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -1,136 +1,119 @@ from __future__ import annotations import os.path +import shutil import pytest from pre_commit import envcontext from pre_commit.languages import r +from pre_commit.prefix import Prefix +from pre_commit.store import _make_local_repo from pre_commit.util import win_exe -from testing.fixtures import make_config_from_repo -from testing.fixtures import make_repo -from tests.repository_test import _get_hook_no_install - - -def _test_r_parsing( - tempdir_factory, - store, - hook_id, - expected_hook_expr={}, - expected_args={}, - config={}, - expect_path_prefix=True, -): - repo_path = 'r_hooks_repo' - path = make_repo(tempdir_factory, repo_path) - config = config or make_config_from_repo(path) - hook = _get_hook_no_install(config, store, hook_id) - ret = r._cmd_from_hook(hook) - expected_cmd = 'Rscript' - expected_opts = ( - '--no-save', '--no-restore', '--no-site-file', '--no-environ', - ) - expected_path = os.path.join( - hook.prefix.prefix_dir if expect_path_prefix else '', - f'{hook_id}.R', - ) - expected = ( - expected_cmd, - *expected_opts, - *(expected_hook_expr or (expected_path,)), - *expected_args, - ) - assert ret == expected +from testing.language_helpers import run_language -def test_r_parsing_file_no_opts_no_args(tempdir_factory, store): - hook_id = 'parse-file-no-opts-no-args' - _test_r_parsing(tempdir_factory, store, hook_id) +def test_r_parsing_file_no_opts_no_args(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript some-script.R', + (), + is_local=False, + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + str(tmp_path.joinpath('some-script.R')), + ) -def test_r_parsing_file_opts_no_args(tempdir_factory, store): +def test_r_parsing_file_opts_no_args(): with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '--no-init', '/path/to/file']) - msg = excinfo.value.args + msg, = excinfo.value.args assert msg == ( - 'The only valid syntax is `Rscript -e {expr}`', - 'or `Rscript path/to/hook/script`', + 'The only valid syntax is `Rscript -e {expr}`' + 'or `Rscript path/to/hook/script`' + ) + + +def test_r_parsing_file_no_opts_args(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript some-script.R', + ('--no-cache',), + is_local=False, + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + str(tmp_path.joinpath('some-script.R')), + '--no-cache', ) -def test_r_parsing_file_no_opts_args(tempdir_factory, store): - hook_id = 'parse-file-no-opts-args' - expected_args = ['--no-cache'] - _test_r_parsing( - tempdir_factory, store, hook_id, expected_args=expected_args, +def test_r_parsing_expr_no_opts_no_args1(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + "Rscript -e '1+1'", + (), + is_local=False, + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + '-e', '1+1', ) -def test_r_parsing_expr_no_opts_no_args1(tempdir_factory, store): - hook_id = 'parse-expr-no-opts-no-args-1' - _test_r_parsing( - tempdir_factory, store, hook_id, expected_hook_expr=('-e', '1+1'), +def test_r_parsing_local_hook_path_is_not_expanded(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript path/to/thing.R', + (), + is_local=True, + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + 'path/to/thing.R', ) -def test_r_parsing_expr_no_opts_no_args2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_no_opts_no_args2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '-e', '1+1', '-e', 'letters']) - msg = execinfo.value.args - assert msg == ('You can supply at most one expression.',) + msg, = excinfo.value.args + assert msg == 'You can supply at most one expression.' -def test_r_parsing_expr_opts_no_args2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_opts_no_args2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate( - [ - 'Rscript', '--vanilla', '-e', '1+1', '-e', 'letters', - ], + ['Rscript', '--vanilla', '-e', '1+1', '-e', 'letters'], ) - msg = execinfo.value.args + msg, = excinfo.value.args assert msg == ( - 'The only valid syntax is `Rscript -e {expr}`', - 'or `Rscript path/to/hook/script`', + 'The only valid syntax is `Rscript -e {expr}`' + 'or `Rscript path/to/hook/script`' ) -def test_r_parsing_expr_args_in_entry2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_args_in_entry2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '-e', 'expr1', '--another-arg']) - msg = execinfo.value.args - assert msg == ('You can supply at most one expression.',) + msg, = excinfo.value.args + assert msg == 'You can supply at most one expression.' -def test_r_parsing_expr_non_Rscirpt(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_non_Rscirpt(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['AnotherScript', '-e', '{{}}']) - msg = execinfo.value.args - assert msg == ('entry must start with `Rscript`.',) - - -def test_r_parsing_file_local(tempdir_factory, store): - path = 'path/to/script.R' - hook_id = 'local-r' - config = { - 'repo': 'local', - 'hooks': [{ - 'id': hook_id, - 'name': 'local-r', - 'entry': f'Rscript {path}', - 'language': 'r', - }], - } - _test_r_parsing( - tempdir_factory, - store, - hook_id=hook_id, - expected_hook_expr=(path,), - config=config, - expect_path_prefix=False, - ) + msg, = excinfo.value.args + assert msg == 'entry must start with `Rscript`.' def test_rscript_exec_relative_to_r_home(): @@ -142,3 +125,99 @@ def test_rscript_exec_relative_to_r_home(): def test_path_rscript_exec_no_r_home_set(): with envcontext.envcontext((('R_HOME', envcontext.UNSET),)): assert r._rscript_exec() == 'Rscript' + + +def test_r_hook(tmp_path): + renv_lock = '''\ +{ + "R": { + "Version": "4.0.3", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "renv": { + "Package": "renv", + "Version": "0.12.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5c0cdb37f063c58cdab3c7e9fbb8bd2c" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "86704667fe0860e4fec35afdfec137f3" + } + } +} +''' + description = '''\ +Package: gli.clu +Title: What the Package Does (One Line, Title Case) +Type: Package +Version: 0.0.0.9000 +Authors@R: + person(given = "First", + family = "Last", + role = c("aut", "cre"), + email = "first.last@example.com", + comment = c(ORCID = "YOUR-ORCID-ID")) +Description: What the package does (one paragraph). +License: `use_mit_license()`, `use_gpl3_license()` or friends to + pick a license +Encoding: UTF-8 +LazyData: true +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.1.1 +Imports: + rprojroot +''' + hello_world_r = '''\ +stopifnot( + packageVersion('rprojroot') == '1.0', + packageVersion('gli.clu') == '0.0.0.9000' +) +cat("Hello, World, from R!\n") +''' + + tmp_path.joinpath('renv.lock').write_text(renv_lock) + tmp_path.joinpath('DESCRIPTION').write_text(description) + tmp_path.joinpath('hello-world.R').write_text(hello_world_r) + renv_dir = tmp_path.joinpath('renv') + renv_dir.mkdir() + shutil.copy( + os.path.join( + os.path.dirname(__file__), + '../../pre_commit/resources/empty_template_activate.R', + ), + renv_dir.joinpath('activate.R'), + ) + + expected = (0, b'Hello, World, from R!\n') + assert run_language(tmp_path, r, 'Rscript hello-world.R') == expected + + +def test_r_inline(tmp_path): + _make_local_repo(str(tmp_path)) + + cmd = '''\ +Rscript -e ' + stopifnot(packageVersion("rprojroot") == "1.0") + cat(commandArgs(trailingOnly = TRUE), "from R!\n", sep=", ") +' +''' + + ret = run_language( + tmp_path, + r, + cmd, + deps=('rprojroot@1.0',), + args=('hi', 'hello'), + ) + assert ret == (0, b'hi, hello, from R!\n') diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 29f3c80..63a16eb 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -71,10 +71,10 @@ def test_install_ruby_default(fake_gem_prefix): @xfailif_windows # pragma: win32 no cover def test_install_ruby_with_version(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, '3.1.0', ()) + ruby.install_environment(fake_gem_prefix, '3.2.0', ()) # Should be able to activate and use rbenv install - with ruby.in_env(fake_gem_prefix, '3.1.0'): + with ruby.in_env(fake_gem_prefix, '3.2.0'): cmd_output('rbenv', 'install', '--help') diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index f011e71..b8167a9 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +from typing import Mapping from unittest import mock import pytest @@ -48,7 +49,9 @@ def test_installs_with_bootstrapped_rustup(tmpdir, language_version): original_find_executable = parse_shebang.find_executable - def mocked_find_executable(exe: str) -> str | None: + def mocked_find_executable( + exe: str, *, env: Mapping[str, str] | None = None, + ) -> str | None: """ Return `None` the first time `find_executable` is called to ensure that the bootstrapping code is executed, then just let the function @@ -59,7 +62,7 @@ def test_installs_with_bootstrapped_rustup(tmpdir, language_version): find_executable_exes.append(exe) if len(find_executable_exes) == 1: return None - return original_find_executable(exe) + return original_find_executable(exe, env=env) with mock.patch.object(parse_shebang, 'find_executable') as find_exe_mck: find_exe_mck.side_effect = mocked_find_executable diff --git a/tests/languages/swift_test.py b/tests/languages/swift_test.py new file mode 100644 index 0000000..e0a8ea4 --- /dev/null +++ b/tests/languages/swift_test.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import sys + +import pytest + +from pre_commit.languages import swift +from testing.language_helpers import run_language + + +@pytest.mark.skipif( + sys.platform == 'win32', + reason='swift is not supported on windows', +) +def test_swift_language(tmp_path): # pragma: win32 no cover + package_swift = '''\ +// swift-tools-version:5.0 +import PackageDescription + +let package = Package( + name: "swift_hooks_repo", + targets: [.target(name: "swift_hooks_repo")] +) +''' + tmp_path.joinpath('Package.swift').write_text(package_swift) + src_dir = tmp_path.joinpath('Sources/swift_hooks_repo') + src_dir.mkdir(parents=True) + src_dir.joinpath('main.swift').write_text('print("Hello, world!")\n') + + expected = (0, b'Hello, world!\n') + assert run_language(tmp_path, swift, 'swift_hooks_repo') == expected |