test_no_shebang.py
1 from pathlib import Path 2 3 import pytest 4 from clint.config import Config 5 from clint.index import SymbolIndex 6 from clint.linter import Position, Range, lint_file 7 from clint.rules import NoShebang 8 9 10 def test_no_shebang(index: SymbolIndex) -> None: 11 config = Config(select={NoShebang.name}) 12 13 # Test file with shebang - should trigger violation 14 code = "#!/usr/bin/env python\nprint('hello')" 15 results = lint_file(Path("test.py"), code, config, index) 16 assert len(results) == 1 17 assert all(isinstance(r.rule, NoShebang) for r in results) 18 assert results[0].range == Range(Position(0, 0)) # First line, first column (0-indexed) 19 20 # Test file without shebang - should not trigger violation 21 code = "print('hello')" 22 results = lint_file(Path("test.py"), code, config, index) 23 assert len(results) == 0 24 25 26 @pytest.mark.parametrize( 27 "shebang", 28 [ 29 "#!/usr/bin/env python", 30 "#!/usr/bin/python", 31 "#!/usr/bin/python3", 32 "#!/usr/bin/env python3", 33 "#! /usr/bin/env python", # With space after #! 34 ], 35 ) 36 def test_no_shebang_various_patterns(index: SymbolIndex, shebang: str) -> None: 37 config = Config(select={NoShebang.name}) 38 39 code = f"{shebang}\nprint('hello')\n" 40 results = lint_file(Path("test.py"), code, config, index) 41 assert all(isinstance(r.rule, NoShebang) for r in results) 42 assert results[0].range == Range(Position(0, 0)) 43 44 45 @pytest.mark.parametrize( 46 "content", 47 [ 48 "", 49 " \n \n", 50 '\n#!/usr/bin/env python\nprint("hello")\n', 51 "# This is a comment\nimport os\n", 52 ], 53 ids=[ 54 "empty_file", 55 "whitespace_only", 56 "shebang_not_on_first_line", 57 "comment_not_shebang", 58 ], 59 ) 60 def test_no_shebang_edge_cases(index: SymbolIndex, content: str) -> None: 61 config = Config(select={NoShebang.name}) 62 63 code = content 64 results = lint_file(Path("test.py"), code, config, index) 65 assert len(results) == 0