summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/clientlib_test.py9
-rw-r--r--tests/commands/init_templatedir_test.py48
-rw-r--r--tests/error_handler_test.py29
-rw-r--r--tests/languages/docker_test.py9
-rw-r--r--tests/languages/python_test.py24
-rw-r--r--tests/main_test.py21
-rw-r--r--tests/store_test.py26
7 files changed, 156 insertions, 10 deletions
diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py
index c48adbd..2e2f738 100644
--- a/tests/clientlib_test.py
+++ b/tests/clientlib_test.py
@@ -30,6 +30,10 @@ def test_check_type_tag_failures(value):
check_type_tag(value)
+def test_check_type_tag_success():
+ check_type_tag('file')
+
+
@pytest.mark.parametrize(
('config_obj', 'expected'), (
(
@@ -110,15 +114,18 @@ def test_validate_config_main_ok():
assert not validate_config_main(('.pre-commit-config.yaml',))
-def test_validate_config_old_list_format_ok(tmpdir):
+def test_validate_config_old_list_format_ok(tmpdir, cap_out):
f = tmpdir.join('cfg.yaml')
f.write('- {repo: meta, hooks: [{id: identity}]}')
assert not validate_config_main((f.strpath,))
+ start = '[WARNING] normalizing pre-commit configuration to a top-level map'
+ assert cap_out.get().startswith(start)
def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog):
f = tmpdir.join('cfg.yaml')
f.write(
+ 'repos:\n'
'- repo: https://gitlab.com/pycqa/flake8\n'
' rev: 3.7.7\n'
' hooks:\n'
diff --git a/tests/commands/init_templatedir_test.py b/tests/commands/init_templatedir_test.py
index d14a171..4e131df 100644
--- a/tests/commands/init_templatedir_test.py
+++ b/tests/commands/init_templatedir_test.py
@@ -1,6 +1,8 @@
import os.path
from unittest import mock
+import pytest
+
import pre_commit.constants as C
from pre_commit.commands.init_templatedir import init_templatedir
from pre_commit.envcontext import envcontext
@@ -90,3 +92,49 @@ def test_init_templatedir_hookspath_set(tmpdir, tempdir_factory, store):
C.CONFIG_FILE, store, target, hook_types=['pre-commit'],
)
assert target.join('hooks/pre-commit').exists()
+
+
+@pytest.mark.parametrize(
+ ('skip', 'commit_retcode', 'commit_output_snippet'),
+ (
+ (True, 0, 'Skipping `pre-commit`.'),
+ (False, 1, f'No {C.CONFIG_FILE} file was found'),
+ ),
+)
+def test_init_templatedir_skip_on_missing_config(
+ tmpdir,
+ tempdir_factory,
+ store,
+ cap_out,
+ skip,
+ commit_retcode,
+ commit_output_snippet,
+):
+ target = str(tmpdir.join('tmpl'))
+ init_git_dir = git_dir(tempdir_factory)
+ with cwd(init_git_dir):
+ cmd_output('git', 'config', 'init.templateDir', target)
+ init_templatedir(
+ C.CONFIG_FILE,
+ store,
+ target,
+ hook_types=['pre-commit'],
+ skip_on_missing_config=skip,
+ )
+
+ lines = cap_out.get().splitlines()
+ assert len(lines) == 1
+ assert lines[0].startswith('pre-commit installed at')
+
+ with envcontext((('GIT_TEMPLATE_DIR', target),)):
+ verify_git_dir = git_dir(tempdir_factory)
+
+ with cwd(verify_git_dir):
+ retcode, output = git_commit(
+ fn=cmd_output_mocked_pre_commit_home,
+ tempdir_factory=tempdir_factory,
+ retcode=None,
+ )
+
+ assert retcode == commit_retcode
+ assert commit_output_snippet in output
diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py
index 833bb8f..d066e57 100644
--- a/tests/error_handler_test.py
+++ b/tests/error_handler_test.py
@@ -1,13 +1,16 @@
import os.path
import re
+import stat
import sys
from unittest import mock
import pytest
from pre_commit import error_handler
+from pre_commit.store import Store
from pre_commit.util import CalledProcessError
from testing.util import cmd_output_mocked_pre_commit_home
+from testing.util import xfailif_windows
@pytest.fixture
@@ -168,3 +171,29 @@ def test_error_handler_no_tty(tempdir_factory):
out_lines = out.splitlines()
assert out_lines[-2] == 'An unexpected error has occurred: ValueError: ☃'
assert out_lines[-1] == f'Check the log at {log_file}'
+
+
+@xfailif_windows # pragma: win32 no cover
+def test_error_handler_read_only_filesystem(mock_store_dir, cap_out, capsys):
+ # a better scenario would be if even the Store crash would be handled
+ # but realistically we're only targetting systems where the Store has
+ # already been set up
+ Store()
+
+ write = (stat.S_IWGRP | stat.S_IWOTH | stat.S_IWUSR)
+ os.chmod(mock_store_dir, os.stat(mock_store_dir).st_mode & ~write)
+
+ with pytest.raises(SystemExit):
+ with error_handler.error_handler():
+ raise ValueError('ohai')
+
+ output = cap_out.get()
+ assert output.startswith(
+ 'An unexpected error has occurred: ValueError: ohai\n'
+ 'Failed to write to log at ',
+ )
+
+ # our cap_out mock is imperfect so the rest of the output goes to capsys
+ out, _ = capsys.readouterr()
+ # the things that normally go to the log file will end up here
+ assert '### version information' in out
diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py
index b65b223..3bed4bf 100644
--- a/tests/languages/docker_test.py
+++ b/tests/languages/docker_test.py
@@ -1,15 +1,6 @@
from unittest import mock
from pre_commit.languages import docker
-from pre_commit.util import CalledProcessError
-
-
-def test_docker_is_running_process_error():
- with mock.patch(
- 'pre_commit.languages.docker.cmd_output_b',
- side_effect=CalledProcessError(1, (), 0, b'', None),
- ):
- assert docker.docker_is_running() is False
def test_docker_fallback_user():
diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py
index c419ad6..29c5a9b 100644
--- a/tests/languages/python_test.py
+++ b/tests/languages/python_test.py
@@ -8,6 +8,7 @@ import pre_commit.constants as C
from pre_commit.envcontext import envcontext
from pre_commit.languages import python
from pre_commit.prefix import Prefix
+from pre_commit.util import make_executable
def test_read_pyvenv_cfg(tmpdir):
@@ -141,3 +142,26 @@ def test_unhealthy_old_virtualenv(python_dir):
os.remove(prefix.path('py_env-default/pyvenv.cfg'))
assert python.healthy(prefix, C.DEFAULT) is False
+
+
+def test_unhealthy_then_replaced(python_dir):
+ prefix, tmpdir = python_dir
+
+ python.install_environment(prefix, C.DEFAULT, ())
+
+ # simulate an exe which returns an old version
+ exe_name = 'python.exe' if sys.platform == 'win32' else 'python'
+ py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name)
+ os.rename(py_exe, f'{py_exe}.tmp')
+
+ with open(py_exe, 'w') as f:
+ f.write('#!/usr/bin/env bash\necho 1.2.3\n')
+ make_executable(py_exe)
+
+ # should be unhealthy due to version mismatch
+ assert python.healthy(prefix, C.DEFAULT) is False
+
+ # now put the exe back and it should be healthy again
+ os.replace(f'{py_exe}.tmp', py_exe)
+
+ assert python.healthy(prefix, C.DEFAULT) is True
diff --git a/tests/main_test.py b/tests/main_test.py
index c472476..f7abeeb 100644
--- a/tests/main_test.py
+++ b/tests/main_test.py
@@ -159,7 +159,28 @@ def test_try_repo(mock_store_dir):
def test_init_templatedir(mock_store_dir):
with mock.patch.object(main, 'init_templatedir') as patch:
main.main(('init-templatedir', 'tdir'))
+
+ assert patch.call_count == 1
+ assert 'tdir' in patch.call_args[0]
+ assert patch.call_args[1]['hook_types'] == ['pre-commit']
+ assert patch.call_args[1]['skip_on_missing_config'] is True
+
+
+def test_init_templatedir_options(mock_store_dir):
+ args = (
+ 'init-templatedir',
+ 'tdir',
+ '--hook-type',
+ 'commit-msg',
+ '--no-allow-missing-config',
+ )
+ with mock.patch.object(main, 'init_templatedir') as patch:
+ main.main(args)
+
assert patch.call_count == 1
+ assert 'tdir' in patch.call_args[0]
+ assert patch.call_args[1]['hook_types'] == ['commit-msg']
+ assert patch.call_args[1]['skip_on_missing_config'] is False
def test_help_cmd_in_empty_directory(
diff --git a/tests/store_test.py b/tests/store_test.py
index 6a4e900..0947144 100644
--- a/tests/store_test.py
+++ b/tests/store_test.py
@@ -1,5 +1,6 @@
import os.path
import sqlite3
+import stat
from unittest import mock
import pytest
@@ -12,6 +13,7 @@ from pre_commit.util import cmd_output
from testing.fixtures import git_dir
from testing.util import cwd
from testing.util import git_commit
+from testing.util import xfailif_windows
def test_our_session_fixture_works():
@@ -217,3 +219,27 @@ def test_select_all_configs_roll_forward(store):
def test_mark_config_as_used_roll_forward(store, tmpdir):
_simulate_pre_1_14_0(store)
test_mark_config_as_used(store, tmpdir)
+
+
+@xfailif_windows # pragma: win32 no cover
+def test_mark_config_as_used_readonly(tmpdir):
+ cfg = tmpdir.join('f').ensure()
+ store_dir = tmpdir.join('store')
+ # make a store, then we'll convert its directory to be readonly
+ assert not Store(str(store_dir)).readonly # directory didn't exist
+ assert not Store(str(store_dir)).readonly # directory did exist
+
+ def _chmod_minus_w(p):
+ st = os.stat(p)
+ os.chmod(p, st.st_mode & ~(stat.S_IWUSR | stat.S_IWOTH | stat.S_IWGRP))
+
+ _chmod_minus_w(store_dir)
+ for fname in os.listdir(store_dir):
+ assert not os.path.isdir(fname)
+ _chmod_minus_w(os.path.join(store_dir, fname))
+
+ store = Store(str(store_dir))
+ assert store.readonly
+ # should be skipped due to readonly
+ store.mark_config_used(str(cfg))
+ assert store.select_all_configs() == []