1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
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'
def test_hook_cmd():
assert lang_base.hook_cmd('echo hi', ()) == ('echo', 'hi')
def test_hook_cmd_hazmat():
ret = lang_base.hook_cmd('pre-commit hazmat cd a echo -- b', ())
assert ret == (
sys.executable, '-m', 'pre_commit.commands.hazmat',
'cd', 'a', 'echo', '--', 'b',
)
|