-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_unused_code.py
More file actions
293 lines (234 loc) · 9.69 KB
/
test_unused_code.py
File metadata and controls
293 lines (234 loc) · 9.69 KB
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
import os
import textwrap
import pytest
from simple_logger.logger import get_logger
from apps.unused_code.unused_code import _git_grep, get_unused_functions, process_file
from tests.utils import get_cli_runner
LOGGER = get_logger(name=__name__)
def test_unused_code():
result = get_cli_runner().invoke(get_unused_functions)
LOGGER.info(f"Result output: {result.output}, exit code: {result.exit_code}, exceptions: {result.exception}")
assert result.exit_code == 1
assert "Is not used anywhere in the code" in result.output
def test_unused_code_file_list():
result = get_cli_runner().invoke(
get_unused_functions,
'--exclude-files "unused_code_file_for_test.py"',
)
LOGGER.info(f"Result output: {result.output}, exit code: {result.exit_code}, exceptions: {result.exception}")
assert result.exit_code == 0
assert "Is not used anywhere in the code" not in result.output
def test_unused_code_function_list_exclude_all():
result = get_cli_runner().invoke(
get_unused_functions,
[
"--exclude-function-prefixes",
"unused_code_",
"--exclude-files",
"manifests/unused_code_file_for_test.py",
],
)
LOGGER.info(f"Result output: {result.output}, exit code: {result.exit_code}, exceptions: {result.exception}")
assert result.exit_code == 0
assert "Is not used anywhere in the code" not in result.output
def test_unused_code_function_list_exclude():
result = get_cli_runner().invoke(get_unused_functions, '--exclude-function-prefixes "unused_code_check_function"')
LOGGER.info(f"Result output: {result.output}, exit code: {result.exit_code}, exceptions: {result.exception}")
assert result.exit_code == 1
assert "Is not used anywhere in the code" in result.output
def test_unused_code_check_skip_with_comment():
result = get_cli_runner().invoke(get_unused_functions)
LOGGER.info(f"Result output: {result.output}, exit code: {result.exit_code}, exceptions: {result.exception}")
assert result.exit_code == 1
assert "skip_with_comment" not in result.output
def test_unused_code_handles_pytest_fixture_parameter_usage(mocker, tmp_path):
# Create a temporary python file with a pytest fixture and a test using it as a parameter
py_file = tmp_path / "tmp_fixture_usage.py"
py_file.write_text(
textwrap.dedent(
"""
import pytest
@pytest.fixture
def sample_fixture():
return 1
def test_something(sample_fixture):
assert sample_fixture == 1
"""
)
)
# Mock grep to simulate: no direct call matches, but parameter usage is detected
def _mock_grep(pattern: str, **kwargs):
# The usage pattern will now match the fixture name in the function signature
if pattern == r"\bsample_fixture\b":
return [f"{py_file.as_posix()}:1:def test_something(sample_fixture): pass"]
return []
mocker.patch("apps.unused_code.unused_code._git_grep", side_effect=_mock_grep)
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
assert result == "" # should not report fixture as unused
def test_unused_code_handles_no_matches_without_crashing(mocker, tmp_path):
# Create a temporary python file with a simple function
py_file = tmp_path / "tmp_simple.py"
py_file.write_text(
textwrap.dedent(
"""
def my_helper():
return 42
"""
)
)
# Mock grep to simulate no matches anywhere
mocker.patch("apps.unused_code.unused_code._git_grep", return_value=[])
# Should return an "unused" message and not crash
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
assert "Is not used anywhere in the code." in result
def test_unused_code_skips_autouse_fixture(tmp_path):
py_file = tmp_path / "tmp_autouse_fixture.py"
py_file.write_text(
textwrap.dedent(
"""
import pytest
@pytest.fixture(autouse=True)
def auto_fixture():
return 1
"""
)
)
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
# should skip autouse fixture and not report unused
assert result == ""
def test_git_grep_raises_on_unexpected_error(mocker):
class FakeCompleted:
def __init__(self):
self.returncode = 2
self.stdout = ""
self.stderr = "fatal: not a git repository"
mocker.patch("apps.unused_code.unused_code.subprocess.run", return_value=FakeCompleted())
with pytest.raises(RuntimeError):
_git_grep(pattern="anything")
def test_commented_usage_is_ignored(mocker, tmp_path):
# Create a temporary python file with a simple function
py_file = tmp_path / "tmp_commented_usage.py"
py_file.write_text(
textwrap.dedent(
"""
def only_here():
return 0
"""
)
)
# Simulate git grep finding only a commented reference
mocker.patch(
"apps.unused_code.unused_code._git_grep",
return_value=["some/other/file.py:12:# only_here() is not really used"],
)
# Should still be reported as unused because usage is commented out
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
assert "Is not used anywhere in the code." in result
def test_git_grep_parsing_handles_windows_paths_with_colons(mocker, tmp_path):
# Create a temporary python file with a simple function
py_file = tmp_path / "tmp_windows_path.py"
py_file.write_text(
textwrap.dedent(
"""
def my_function():
return 42
"""
)
)
# Simulate git grep output with Windows-style paths containing drive letters and colons
# Format: path:line-number:line-content
# Windows paths like C:\path\to\file.py:123:content would break with split(":", 2)
# but should work correctly with rsplit(":", 2)
mocker.patch(
"apps.unused_code.unused_code._git_grep",
return_value=[
"C:\\Users\\test\\project\\file.py:25:result = my_function()",
"/some/unix/path/with:colon/file.py:30:my_function() # usage found",
"D:\\Another\\Windows\\Path\\test.py:15: my_function() # another usage",
],
)
# Should detect the function as used (not report as unused)
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
assert result == "" # Empty string means function is used, not unused
def test_git_grep_parsing_handles_malformed_output_gracefully(mocker, tmp_path):
# Create a temporary python file with a simple function
py_file = tmp_path / "tmp_malformed.py"
py_file.write_text(
textwrap.dedent(
"""
def my_function():
return 42
"""
)
)
# Simulate git grep output with malformed entries (missing parts)
# The parsing should skip malformed entries and continue processing
mocker.patch(
"apps.unused_code.unused_code._git_grep",
return_value=[
"malformed_line_without_colons", # Should be skipped
"only:one:colon", # Should be skipped (only 2 parts after rsplit)
"C:\\valid\\path\\file.py:25:result = my_function()", # Valid - should be processed
],
)
# Should detect the function as used despite malformed entries
result = process_file(py_file=str(py_file), func_ignore_prefix=[], file_ignore_list=[])
assert result == "" # Empty string means function is used, not unused
def test_function_as_argument_is_used():
result = process_file(
py_file="tests/unused_code/manifests/functions_as_args.py",
func_ignore_prefix=[],
file_ignore_list=[],
)
assert result == ""
def test_unused_code_with_file_path_no_unused():
result = get_cli_runner().invoke(
get_unused_functions,
["--file-path", "tests/unused_code/manifests/functions_as_args.py"],
)
assert result.exit_code == 0
assert "Is not used anywhere in the code" not in result.output
def test_unused_code_with_file_path_with_unused():
result = get_cli_runner().invoke(
get_unused_functions,
["--file-path", "tests/unused_code/manifests/unused_code_file_for_test.py"],
)
assert result.exit_code == 1
assert "Is not used anywhere in the code" in result.output
def test_unused_code_with_directory():
result = get_cli_runner().invoke(get_unused_functions, ["--directory", "tests/unused_code/manifests/"])
assert result.exit_code == 1
assert "Is not used anywhere in the code" in result.output
def test_unused_code_with_config_file():
result = get_cli_runner().invoke(
get_unused_functions,
[
"--config-file-path",
"tests/unused_code/manifests/test_config.yaml",
"--directory",
"tests/unused_code/manifests/",
],
)
assert result.exit_code == 0
assert "Is not used anywhere in the code" not in result.output
def test_unused_code_with_file_path_as_dir():
result = get_cli_runner().invoke(get_unused_functions, ["--file-path", "tests/unused_code/"])
assert result.exit_code == 1
assert isinstance(result.exception, SystemExit)
def test_unused_code_with_directory_as_file():
result = get_cli_runner().invoke(
get_unused_functions,
["--directory", "tests/unused_code/test_unused_code.py"],
)
assert result.exit_code == 1
assert isinstance(result.exception, SystemExit)
def test_unused_code_not_a_git_repo(tmp_path):
original_cwd = os.getcwd()
try:
os.chdir(tmp_path)
# tmp_path is not a git repo, so this should fail
result = get_cli_runner().invoke(get_unused_functions)
assert result.exit_code == 1
assert isinstance(result.exception, SystemExit)
finally:
os.chdir(original_cwd)