166 lines
4.7 KiB
Python
166 lines
4.7 KiB
Python
from __future__ import annotations
|
|
|
|
import os.path
|
|
import sys
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
import pre_commit.constants as C
|
|
from pre_commit import lang_base
|
|
from pre_commit import parse_shebang
|
|
from pre_commit import xargs
|
|
from pre_commit.prefix import Prefix
|
|
from pre_commit.util import CalledProcessError
|
|
|
|
|
|
@pytest.fixture
|
|
def find_exe_mck():
|
|
with mock.patch.object(parse_shebang, 'find_executable') as mck:
|
|
yield mck
|
|
|
|
|
|
@pytest.fixture
|
|
def homedir_mck():
|
|
def fake_expanduser(pth):
|
|
assert pth == '~'
|
|
return os.path.normpath('/home/me')
|
|
|
|
with mock.patch.object(os.path, 'expanduser', fake_expanduser):
|
|
yield
|
|
|
|
|
|
def test_exe_exists_does_not_exist(find_exe_mck, homedir_mck):
|
|
find_exe_mck.return_value = None
|
|
assert lang_base.exe_exists('ruby') is False
|
|
|
|
|
|
def test_exe_exists_exists(find_exe_mck, homedir_mck):
|
|
find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby')
|
|
assert lang_base.exe_exists('ruby') is True
|
|
|
|
|
|
def test_exe_exists_false_if_shim(find_exe_mck, homedir_mck):
|
|
find_exe_mck.return_value = os.path.normpath('/foo/shims/ruby')
|
|
assert lang_base.exe_exists('ruby') is False
|
|
|
|
|
|
def test_exe_exists_false_if_homedir(find_exe_mck, homedir_mck):
|
|
find_exe_mck.return_value = os.path.normpath('/home/me/somedir/ruby')
|
|
assert lang_base.exe_exists('ruby') is False
|
|
|
|
|
|
def test_exe_exists_commonpath_raises_ValueError(find_exe_mck, homedir_mck):
|
|
find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby')
|
|
with mock.patch.object(os.path, 'commonpath', side_effect=ValueError):
|
|
assert lang_base.exe_exists('ruby') is True
|
|
|
|
|
|
def test_exe_exists_true_when_homedir_is_slash(find_exe_mck):
|
|
find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby')
|
|
with mock.patch.object(os.path, 'expanduser', return_value=os.sep):
|
|
assert lang_base.exe_exists('ruby') is True
|
|
|
|
|
|
def test_basic_get_default_version():
|
|
assert lang_base.basic_get_default_version() == C.DEFAULT
|
|
|
|
|
|
def test_basic_health_check():
|
|
assert lang_base.basic_health_check(Prefix('.'), 'default') is None
|
|
|
|
|
|
def test_failed_setup_command_does_not_unicode_error():
|
|
script = (
|
|
'import sys\n'
|
|
"sys.stderr.buffer.write(b'\\x81\\xfe')\n"
|
|
'raise SystemExit(1)\n'
|
|
)
|
|
|
|
# an assertion that this does not raise `UnicodeError`
|
|
with pytest.raises(CalledProcessError):
|
|
lang_base.setup_cmd(Prefix('.'), (sys.executable, '-c', script))
|
|
|
|
|
|
def test_environment_dir(tmp_path):
|
|
ret = lang_base.environment_dir(Prefix(tmp_path), 'langenv', 'default')
|
|
assert ret == f'{tmp_path}{os.sep}langenv-default'
|
|
|
|
|
|
def test_assert_version_default():
|
|
with pytest.raises(AssertionError) as excinfo:
|
|
lang_base.assert_version_default('lang', '1.2.3')
|
|
msg, = excinfo.value.args
|
|
assert msg == (
|
|
'for now, pre-commit requires system-installed lang -- '
|
|
'you selected `language_version: 1.2.3`'
|
|
)
|
|
|
|
|
|
def test_assert_no_additional_deps():
|
|
with pytest.raises(AssertionError) as excinfo:
|
|
lang_base.assert_no_additional_deps('lang', ['hmmm'])
|
|
msg, = excinfo.value.args
|
|
assert msg == (
|
|
'for now, pre-commit does not support additional_dependencies for '
|
|
'lang -- '
|
|
"you selected `additional_dependencies: ['hmmm']`"
|
|
)
|
|
|
|
|
|
def test_no_env_noop(tmp_path):
|
|
before = os.environ.copy()
|
|
with lang_base.no_env(Prefix(tmp_path), '1.2.3'):
|
|
inside = os.environ.copy()
|
|
after = os.environ.copy()
|
|
assert before == inside == after
|
|
|
|
|
|
@pytest.fixture
|
|
def cpu_count_mck():
|
|
with mock.patch.object(xargs, 'cpu_count', return_value=4):
|
|
yield
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
('var', 'expected'),
|
|
(
|
|
('PRE_COMMIT_NO_CONCURRENCY', 1),
|
|
('TRAVIS', 2),
|
|
(None, 4),
|
|
),
|
|
)
|
|
def test_target_concurrency(cpu_count_mck, var, expected):
|
|
with mock.patch.dict(os.environ, {var: '1'} if var else {}, clear=True):
|
|
assert lang_base.target_concurrency() == expected
|
|
|
|
|
|
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 lang_base._shuffled(seq) == expected
|
|
|
|
|
|
def test_xargs_require_serial_is_not_shuffled():
|
|
ret, out = lang_base.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'
|
|
|
|
|
|
def test_basic_run_hook(tmp_path):
|
|
ret, out = lang_base.basic_run_hook(
|
|
Prefix(tmp_path),
|
|
'echo hi',
|
|
['hello'],
|
|
['file', 'file', 'file'],
|
|
is_local=False,
|
|
require_serial=False,
|
|
color=False,
|
|
)
|
|
assert ret == 0
|
|
out = out.replace(b'\r\n', b'\n')
|
|
assert out == b'hi hello file file file\n'
|