summaryrefslogtreecommitdiffstats
path: root/tests/main_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/main_test.py')
-rw-r--r--tests/main_test.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/tests/main_test.py b/tests/main_test.py
new file mode 100644
index 0000000..c472476
--- /dev/null
+++ b/tests/main_test.py
@@ -0,0 +1,189 @@
+import argparse
+import os.path
+from unittest import mock
+
+import pytest
+
+import pre_commit.constants as C
+from pre_commit import main
+from pre_commit.error_handler import FatalError
+from testing.auto_namedtuple import auto_namedtuple
+
+
+@pytest.mark.parametrize(
+ ('argv', 'expected'),
+ (
+ ((), ['f']),
+ (('--f', 'x'), ['x']),
+ (('--f', 'x', '--f', 'y'), ['x', 'y']),
+ ),
+)
+def test_append_replace_default(argv, expected):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--f', action=main.AppendReplaceDefault, default=['f'])
+ assert parser.parse_args(argv).f == expected
+
+
+def _args(**kwargs):
+ kwargs.setdefault('command', 'help')
+ kwargs.setdefault('config', C.CONFIG_FILE)
+ return argparse.Namespace(**kwargs)
+
+
+def test_adjust_args_and_chdir_not_in_git_dir(in_tmpdir):
+ with pytest.raises(FatalError):
+ main._adjust_args_and_chdir(_args())
+
+
+def test_adjust_args_and_chdir_in_dot_git_dir(in_git_dir):
+ with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError):
+ main._adjust_args_and_chdir(_args())
+
+
+def test_adjust_args_and_chdir_noop(in_git_dir):
+ args = _args(command='run', files=['f1', 'f2'])
+ main._adjust_args_and_chdir(args)
+ assert os.getcwd() == in_git_dir
+ assert args.config == C.CONFIG_FILE
+ assert args.files == ['f1', 'f2']
+
+
+def test_adjust_args_and_chdir_relative_things(in_git_dir):
+ in_git_dir.join('foo/cfg.yaml').ensure()
+ in_git_dir.join('foo').chdir()
+
+ args = _args(command='run', files=['f1', 'f2'], config='cfg.yaml')
+ main._adjust_args_and_chdir(args)
+ assert os.getcwd() == in_git_dir
+ assert args.config == os.path.join('foo', 'cfg.yaml')
+ assert args.files == [os.path.join('foo', 'f1'), os.path.join('foo', 'f2')]
+
+
+def test_adjust_args_and_chdir_non_relative_config(in_git_dir):
+ in_git_dir.join('foo').ensure_dir().chdir()
+
+ args = _args()
+ main._adjust_args_and_chdir(args)
+ assert os.getcwd() == in_git_dir
+ assert args.config == C.CONFIG_FILE
+
+
+def test_adjust_args_try_repo_repo_relative(in_git_dir):
+ in_git_dir.join('foo').ensure_dir().chdir()
+
+ args = _args(command='try-repo', repo='../foo', files=[])
+ assert args.repo is not None
+ assert os.path.exists(args.repo)
+ main._adjust_args_and_chdir(args)
+ assert os.getcwd() == in_git_dir
+ assert os.path.exists(args.repo)
+ assert args.repo == 'foo'
+
+
+FNS = (
+ 'autoupdate', 'clean', 'gc', 'hook_impl', 'install', 'install_hooks',
+ 'migrate_config', 'run', 'sample_config', 'uninstall',
+)
+CMDS = tuple(fn.replace('_', '-') for fn in FNS)
+
+
+@pytest.fixture
+def mock_commands():
+ mcks = {fn: mock.patch.object(main, fn).start() for fn in FNS}
+ ret = auto_namedtuple(**mcks)
+ yield ret
+ for mck in ret:
+ mck.stop()
+
+
+@pytest.fixture
+def argparse_parse_args_spy():
+ parse_args_mock = mock.Mock()
+
+ original_parse_args = argparse.ArgumentParser.parse_args
+
+ def fake_parse_args(self, args):
+ # call our spy object
+ parse_args_mock(args)
+ return original_parse_args(self, args)
+
+ with mock.patch.object(
+ argparse.ArgumentParser, 'parse_args', fake_parse_args,
+ ):
+ yield parse_args_mock
+
+
+def assert_only_one_mock_called(mock_objs):
+ total_call_count = sum(mock_obj.call_count for mock_obj in mock_objs)
+ assert total_call_count == 1
+
+
+def test_overall_help(mock_commands):
+ with pytest.raises(SystemExit):
+ main.main(['--help'])
+
+
+def test_help_command(mock_commands, argparse_parse_args_spy):
+ with pytest.raises(SystemExit):
+ main.main(['help'])
+
+ argparse_parse_args_spy.assert_has_calls([
+ mock.call(['help']),
+ mock.call(['--help']),
+ ])
+
+
+def test_help_other_command(mock_commands, argparse_parse_args_spy):
+ with pytest.raises(SystemExit):
+ main.main(['help', 'run'])
+
+ argparse_parse_args_spy.assert_has_calls([
+ mock.call(['help', 'run']),
+ mock.call(['run', '--help']),
+ ])
+
+
+@pytest.mark.parametrize('command', CMDS)
+def test_all_cmds(command, mock_commands, mock_store_dir):
+ main.main((command,))
+ assert getattr(mock_commands, command.replace('-', '_')).call_count == 1
+ assert_only_one_mock_called(mock_commands)
+
+
+def test_try_repo(mock_store_dir):
+ with mock.patch.object(main, 'try_repo') as patch:
+ main.main(('try-repo', '.'))
+ assert patch.call_count == 1
+
+
+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
+
+
+def test_help_cmd_in_empty_directory(
+ in_tmpdir,
+ mock_commands,
+ argparse_parse_args_spy,
+):
+ with pytest.raises(SystemExit):
+ main.main(['help', 'run'])
+
+ argparse_parse_args_spy.assert_has_calls([
+ mock.call(['help', 'run']),
+ mock.call(['run', '--help']),
+ ])
+
+
+def test_expected_fatal_error_no_git_repo(in_tmpdir, cap_out, mock_store_dir):
+ with pytest.raises(SystemExit):
+ main.main([])
+ log_file = os.path.join(mock_store_dir, 'pre-commit.log')
+ cap_out_lines = cap_out.get().splitlines()
+ assert (
+ cap_out_lines[-2] ==
+ 'An error has occurred: FatalError: git failed. '
+ 'Is it installed, and are you in a Git repository directory?'
+ )
+ assert cap_out_lines[-1] == f'Check the log at {log_file}'