blob: 82d03e3df386f13d3942f5696a8eafdc98f84d17 [file] [log] [blame]
Anthony Sottile8f615292022-01-15 19:24:05 -05001from __future__ import annotations
2
Max Rozentsveyg5195ba32020-05-16 23:59:08 -04003import os
4import sys
5
Chris Kuehl13991f02017-07-02 21:00:28 -07006import pytest
7
Max Rozentsveyg5195ba32020-05-16 23:59:08 -04008from pre_commit_hooks import check_executables_have_shebangs
Chris Kuehl13991f02017-07-02 21:00:28 -07009from pre_commit_hooks.check_executables_have_shebangs import main
Max Rozentsveyg5195ba32020-05-16 23:59:08 -040010from pre_commit_hooks.util import cmd_output
11
12skip_win32 = pytest.mark.skipif(
13 sys.platform == 'win32',
14 reason="non-git checks aren't relevant on windows",
15)
Chris Kuehl13991f02017-07-02 21:00:28 -070016
17
Max Rozentsveyg5195ba32020-05-16 23:59:08 -040018@skip_win32 # pragma: win32 no cover
Anthony Sottilee9aea742017-07-15 12:56:51 -070019@pytest.mark.parametrize(
20 'content', (
21 b'#!/bin/bash\nhello world\n',
22 b'#!/usr/bin/env python3.6',
23 b'#!python',
Anthony Sottilef5c42a02020-02-05 11:10:42 -080024 '#!☃'.encode(),
Anthony Sottilee9aea742017-07-15 12:56:51 -070025 ),
26)
Chris Kuehl13991f02017-07-02 21:00:28 -070027def test_has_shebang(content, tmpdir):
28 path = tmpdir.join('path')
29 path.write(content, 'wb')
Max Rozentsveygf35bfed2020-05-20 12:07:45 -040030 assert main((str(path),)) == 0
Chris Kuehl13991f02017-07-02 21:00:28 -070031
32
Max Rozentsveyg5195ba32020-05-16 23:59:08 -040033@skip_win32 # pragma: win32 no cover
Anthony Sottilee9aea742017-07-15 12:56:51 -070034@pytest.mark.parametrize(
35 'content', (
36 b'',
37 b' #!python\n',
38 b'\n#!python\n',
39 b'python\n',
Anthony Sottilef5c42a02020-02-05 11:10:42 -080040 '☃'.encode(),
Anthony Sottilee9aea742017-07-15 12:56:51 -070041 ),
42)
Chris Kuehl13991f02017-07-02 21:00:28 -070043def test_bad_shebang(content, tmpdir, capsys):
44 path = tmpdir.join('path')
45 path.write(content, 'wb')
Max Rozentsveygf35bfed2020-05-20 12:07:45 -040046 assert main((str(path),)) == 1
Chris Kuehl13991f02017-07-02 21:00:28 -070047 _, stderr = capsys.readouterr()
Anthony Sottilef5c42a02020-02-05 11:10:42 -080048 assert stderr.startswith(f'{path}: marked executable but')
Max Rozentsveyg5195ba32020-05-16 23:59:08 -040049
50
51def test_check_git_filemode_passing(tmpdir):
52 with tmpdir.as_cwd():
53 cmd_output('git', 'init', '.')
54
55 f = tmpdir.join('f')
56 f.write('#!/usr/bin/env bash')
57 f_path = str(f)
58 cmd_output('chmod', '+x', f_path)
59 cmd_output('git', 'add', f_path)
60 cmd_output('git', 'update-index', '--chmod=+x', f_path)
61
62 g = tmpdir.join('g').ensure()
63 g_path = str(g)
64 cmd_output('git', 'add', g_path)
65
66 # this is potentially a problem, but not something the script intends
67 # to check for -- we're only making sure that things that are
68 # executable have shebangs
69 h = tmpdir.join('h')
70 h.write('#!/usr/bin/env bash')
71 h_path = str(h)
72 cmd_output('git', 'add', h_path)
73
74 files = (f_path, g_path, h_path)
75 assert check_executables_have_shebangs._check_git_filemode(files) == 0
76
77
Timothée Mazzucotelli4faed342020-07-29 09:57:24 +020078def test_check_git_filemode_passing_unusual_characters(tmpdir):
79 with tmpdir.as_cwd():
80 cmd_output('git', 'init', '.')
81
82 f = tmpdir.join('mañana.txt')
83 f.write('#!/usr/bin/env bash')
84 f_path = str(f)
85 cmd_output('chmod', '+x', f_path)
86 cmd_output('git', 'add', f_path)
87 cmd_output('git', 'update-index', '--chmod=+x', f_path)
88
89 files = (f_path,)
90 assert check_executables_have_shebangs._check_git_filemode(files) == 0
91
92
Max Rozentsveyg5195ba32020-05-16 23:59:08 -040093def test_check_git_filemode_failing(tmpdir):
94 with tmpdir.as_cwd():
95 cmd_output('git', 'init', '.')
96
97 f = tmpdir.join('f').ensure()
98 f_path = str(f)
99 cmd_output('chmod', '+x', f_path)
100 cmd_output('git', 'add', f_path)
101 cmd_output('git', 'update-index', '--chmod=+x', f_path)
102
103 files = (f_path,)
104 assert check_executables_have_shebangs._check_git_filemode(files) == 1
105
106
107@pytest.mark.parametrize(
108 ('content', 'mode', 'expected'),
109 (
110 pytest.param('#!python', '+x', 0, id='shebang with executable'),
111 pytest.param('#!python', '-x', 0, id='shebang without executable'),
112 pytest.param('', '+x', 1, id='no shebang with executable'),
113 pytest.param('', '-x', 0, id='no shebang without executable'),
114 ),
115)
116def test_git_executable_shebang(temp_git_dir, content, mode, expected):
117 with temp_git_dir.as_cwd():
118 path = temp_git_dir.join('path')
119 path.write(content)
120 cmd_output('git', 'add', str(path))
121 cmd_output('chmod', mode, str(path))
122 cmd_output('git', 'update-index', f'--chmod={mode}', str(path))
123
Max R7848fcf2020-05-18 21:46:53 -0400124 # simulate how identify chooses that something is executable
Max Rozentsveyg5195ba32020-05-16 23:59:08 -0400125 filenames = [path for path in [str(path)] if os.access(path, os.X_OK)]
126
127 assert main(filenames) == expected