diff-cover 9.1.0__tar.gz → 9.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diff_cover-9.1.0 → diff_cover-9.2.0}/PKG-INFO +13 -1
- {diff_cover-9.1.0 → diff_cover-9.2.0}/README.rst +12 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/diff_cover_tool.py +14 -1
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/diff_reporter.py +48 -19
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/violationsreporters/violations_reporter.py +26 -2
- {diff_cover-9.1.0 → diff_cover-9.2.0}/pyproject.toml +3 -3
- diff_cover-9.2.0/tests/fixtures/coverage_missing_lines.xml +24 -0
- diff_cover-9.2.0/tests/fixtures/expand_console_report.txt +10 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_diff_reporter.py +51 -4
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_integration.py +14 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_violations_reporter.py +61 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/LICENSE +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/__init__.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/command_runner.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/config_parser.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/diff_quality_tool.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/git_diff.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/git_path.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/hook.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/hookspecs.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/report_generator.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/snippets.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/console_coverage_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/console_quality_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/external_style.css +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/html_coverage_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/html_quality_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/markdown_coverage_report.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/markdown_quality_report.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/snippet_content.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/snippet_content.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/snippet_content.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/templates/snippet_style.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/util.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/violationsreporters/__init__.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/violationsreporters/base.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/violationsreporters/java_violations_reporter.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/__init__.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/add_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/add_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/changed_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/changed_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/coverage.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/coverage1.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/coverage2.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/delete_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/delete_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/dotnet_coverage.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/dotnet_coverage_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/empty.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/empty_pycodestyle_violations.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/external_css_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/external_style.css +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_add.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_changed.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_code_dupe.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_delete.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_dotnet.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_external_css.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_lua.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_moved.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_mult.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_subdir.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_unicode.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_violations.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/git_diff_violations_two_files.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/hello.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/hi.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/html_report_empty.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/html_report_one_snippet.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/html_report_two_snippets.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/lcov.info +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/lua_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/luacoverage.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/markdown_report_one_snippet.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/markdown_report_two_snippets.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/moved_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/moved_coverage.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/moved_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/mult_inputs_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/mult_inputs_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pycodestyle_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pycodestyle_violations_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pycodestyle_violations_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pycodestyle_violations_report_external_css.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pyflakes_two_files.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pyflakes_violations_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pyflakes_violations_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_dupe.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_dupe_violations_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_violations_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_violations_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylint_violations_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pylintrc +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/show_uncovered_lines_console.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet.css +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_8859.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_arabic_output.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_default.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_invalid_violations.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_list.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_list.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_list2.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_list3.md +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_no_filename_ext.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_src.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_src2.cpp +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_src3.cpp +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_unicode.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_unicode.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/snippet_unicode_html_output.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/subdir_coverage_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/subdir_coverage_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/test_src.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/unicode_console_report.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/unicode_coverage.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/unicode_html_report.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/unicode_test_src.txt +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/violations_test_file.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/helpers.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/snippet_list_unicode.html +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_clover_violations_reporter/test.xml +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_clover_violations_reporter.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_config_parser.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_diff_cover_main.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_diff_cover_tool.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_diff_quality_main.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_git_diff.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_git_diff_file.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_git_path.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_java_violations_reporter.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_report_generator.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_snippets.py +0 -0
- {diff_cover-9.1.0 → diff_cover-9.2.0}/tests/test_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: diff_cover
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.2.0
|
|
4
4
|
Summary: Run coverage and linting reports on diffs
|
|
5
5
|
Home-page: https://github.com/Bachmann1234/diff-cover
|
|
6
6
|
License: Apache-2.0
|
|
@@ -307,6 +307,18 @@ It can be enabled by using the ``-q``/``--quiet`` flag:
|
|
|
307
307
|
|
|
308
308
|
If enabled, the tool will only print errors and failures but no information or warning messages.
|
|
309
309
|
|
|
310
|
+
Compatibility with multi-line statements
|
|
311
|
+
----------------------------------------
|
|
312
|
+
``diff-cover`` relies on the comparison of diff reports and coverage reports, and does not report
|
|
313
|
+
lines that appear in one and not in the other. While diff reports list all lines that changed,
|
|
314
|
+
coverage reports usually list code statements. As a result, a change in a multi-line statement may not be analyzed by ``diff-cover``.
|
|
315
|
+
|
|
316
|
+
As a workaround, you can use the argument ``--expand-coverage-report``: lines not appearing in the coverage reports will be added to them with the same number of hits as the previously reported line. ``diff-cover`` will then perform diff coverage analysis on all changed lines.
|
|
317
|
+
|
|
318
|
+
Notes:
|
|
319
|
+
- This argument is only available for XML coverage reports.
|
|
320
|
+
- This workaround is designed under the assumption that the coverage tool reports untested statements with hits set to 0, and it reports statements based on the opening line.
|
|
321
|
+
|
|
310
322
|
Configuration files
|
|
311
323
|
-------------------
|
|
312
324
|
Both tools allow users to specify the options in a configuration file with `--config-file`/`-c`:
|
|
@@ -274,6 +274,18 @@ It can be enabled by using the ``-q``/``--quiet`` flag:
|
|
|
274
274
|
|
|
275
275
|
If enabled, the tool will only print errors and failures but no information or warning messages.
|
|
276
276
|
|
|
277
|
+
Compatibility with multi-line statements
|
|
278
|
+
----------------------------------------
|
|
279
|
+
``diff-cover`` relies on the comparison of diff reports and coverage reports, and does not report
|
|
280
|
+
lines that appear in one and not in the other. While diff reports list all lines that changed,
|
|
281
|
+
coverage reports usually list code statements. As a result, a change in a multi-line statement may not be analyzed by ``diff-cover``.
|
|
282
|
+
|
|
283
|
+
As a workaround, you can use the argument ``--expand-coverage-report``: lines not appearing in the coverage reports will be added to them with the same number of hits as the previously reported line. ``diff-cover`` will then perform diff coverage analysis on all changed lines.
|
|
284
|
+
|
|
285
|
+
Notes:
|
|
286
|
+
- This argument is only available for XML coverage reports.
|
|
287
|
+
- This workaround is designed under the assumption that the coverage tool reports untested statements with hits set to 0, and it reports statements based on the opening line.
|
|
288
|
+
|
|
277
289
|
Configuration files
|
|
278
290
|
-------------------
|
|
279
291
|
Both tools allow users to specify the options in a configuration file with `--config-file`/`-c`:
|
|
@@ -41,6 +41,9 @@ DIFF_RANGE_NOTATION_HELP = (
|
|
|
41
41
|
)
|
|
42
42
|
QUIET_HELP = "Only print errors and failures"
|
|
43
43
|
SHOW_UNCOVERED = "Show uncovered lines on the console"
|
|
44
|
+
EXPAND_COVERAGE_REPORT = (
|
|
45
|
+
"Append missing lines in coverage reports based on the hits of the previous line."
|
|
46
|
+
)
|
|
44
47
|
INCLUDE_UNTRACKED_HELP = "Include untracked files"
|
|
45
48
|
CONFIG_FILE_HELP = "The configuration file to use"
|
|
46
49
|
DIFF_FILE_HELP = "The diff file to use"
|
|
@@ -93,6 +96,13 @@ def parse_coverage_args(argv):
|
|
|
93
96
|
"--show-uncovered", action="store_true", default=None, help=SHOW_UNCOVERED
|
|
94
97
|
)
|
|
95
98
|
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--expand-coverage-report",
|
|
101
|
+
action="store_true",
|
|
102
|
+
default=None,
|
|
103
|
+
help=EXPAND_COVERAGE_REPORT,
|
|
104
|
+
)
|
|
105
|
+
|
|
96
106
|
parser.add_argument(
|
|
97
107
|
"--external-css-file",
|
|
98
108
|
metavar="FILENAME",
|
|
@@ -183,6 +193,7 @@ def parse_coverage_args(argv):
|
|
|
183
193
|
"ignore_whitespace": False,
|
|
184
194
|
"diff_range_notation": "...",
|
|
185
195
|
"quiet": False,
|
|
196
|
+
"expand_coverage_report": False,
|
|
186
197
|
}
|
|
187
198
|
|
|
188
199
|
return get_config(parser=parser, argv=argv, defaults=defaults, tool=Tool.DIFF_COVER)
|
|
@@ -204,6 +215,7 @@ def generate_coverage_report(
|
|
|
204
215
|
src_roots=None,
|
|
205
216
|
quiet=False,
|
|
206
217
|
show_uncovered=False,
|
|
218
|
+
expand_coverage_report=False,
|
|
207
219
|
):
|
|
208
220
|
"""
|
|
209
221
|
Generate the diff coverage report, using kwargs from `parse_args()`.
|
|
@@ -231,7 +243,7 @@ def generate_coverage_report(
|
|
|
231
243
|
if len(xml_roots) > 0 and len(lcov_roots) > 0:
|
|
232
244
|
raise ValueError(f"Mixing LCov and XML reports is not supported yet")
|
|
233
245
|
elif len(xml_roots) > 0:
|
|
234
|
-
coverage = XmlCoverageReporter(xml_roots, src_roots)
|
|
246
|
+
coverage = XmlCoverageReporter(xml_roots, src_roots, expand_coverage_report)
|
|
235
247
|
else:
|
|
236
248
|
coverage = LcovCoverageReporter(lcov_roots, src_roots)
|
|
237
249
|
|
|
@@ -308,6 +320,7 @@ def main(argv=None, directory=None):
|
|
|
308
320
|
src_roots=arg_dict["src_roots"],
|
|
309
321
|
quiet=quiet,
|
|
310
322
|
show_uncovered=arg_dict["show_uncovered"],
|
|
323
|
+
expand_coverage_report=arg_dict["expand_coverage_report"],
|
|
311
324
|
)
|
|
312
325
|
|
|
313
326
|
if percent_covered >= fail_under:
|
|
@@ -165,18 +165,31 @@ class GitDiffReporter(BaseDiffReporter):
|
|
|
165
165
|
|
|
166
166
|
# Get the diff dictionary
|
|
167
167
|
diff_dict = self._git_diff()
|
|
168
|
-
|
|
169
168
|
# include untracked files
|
|
170
169
|
if self._include_untracked:
|
|
171
170
|
for path in self._git_diff_tool.untracked():
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
if not self._validate_path_to_diff(path):
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
num_lines = self._get_file_lines(path)
|
|
174
175
|
diff_dict[path] = list(range(1, num_lines + 1))
|
|
175
176
|
|
|
176
177
|
# Return the changed file paths (dict keys)
|
|
177
178
|
# in alphabetical order
|
|
178
179
|
return sorted(diff_dict.keys(), key=lambda x: x.lower())
|
|
179
180
|
|
|
181
|
+
@staticmethod
|
|
182
|
+
def _get_file_lines(path):
|
|
183
|
+
"""
|
|
184
|
+
Return the number of lines in a file.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
with open(path, encoding="utf-8") as file_handle:
|
|
189
|
+
return len(file_handle.readlines())
|
|
190
|
+
except UnicodeDecodeError:
|
|
191
|
+
return 0
|
|
192
|
+
|
|
180
193
|
def lines_changed(self, src_path):
|
|
181
194
|
"""
|
|
182
195
|
See base class docstring.
|
|
@@ -224,23 +237,16 @@ class GitDiffReporter(BaseDiffReporter):
|
|
|
224
237
|
diff_dict = self._parse_diff_str(diff_str)
|
|
225
238
|
|
|
226
239
|
for src_path, (added_lines, deleted_lines) in diff_dict.items():
|
|
227
|
-
if self.
|
|
240
|
+
if not self._validate_path_to_diff(src_path):
|
|
228
241
|
continue
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
# Remove any lines from the dict that have been deleted
|
|
238
|
-
# Include any lines that have been added
|
|
239
|
-
result_dict[src_path] = [
|
|
240
|
-
line
|
|
241
|
-
for line in result_dict.get(src_path, [])
|
|
242
|
-
if line not in deleted_lines
|
|
243
|
-
] + added_lines
|
|
242
|
+
|
|
243
|
+
# Remove any lines from the dict that have been deleted
|
|
244
|
+
# Include any lines that have been added
|
|
245
|
+
result_dict[src_path] = [
|
|
246
|
+
line
|
|
247
|
+
for line in result_dict.get(src_path, [])
|
|
248
|
+
if line not in deleted_lines
|
|
249
|
+
] + added_lines
|
|
244
250
|
|
|
245
251
|
# Eliminate repeats and order line numbers
|
|
246
252
|
for src_path, lines in result_dict.items():
|
|
@@ -252,6 +258,29 @@ class GitDiffReporter(BaseDiffReporter):
|
|
|
252
258
|
# Return the diff cache
|
|
253
259
|
return self._diff_dict
|
|
254
260
|
|
|
261
|
+
def _validate_path_to_diff(self, src_path: str) -> bool:
|
|
262
|
+
"""
|
|
263
|
+
Validate if a path should be included in the diff.
|
|
264
|
+
|
|
265
|
+
Returns True if the path should be included, otherwise False.
|
|
266
|
+
|
|
267
|
+
A path should be excluded if:
|
|
268
|
+
- If the path is excluded
|
|
269
|
+
- If the path has an extension that is not supported
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
if self._is_path_excluded(src_path):
|
|
273
|
+
return False
|
|
274
|
+
|
|
275
|
+
# If no _supported_extensions provided, or extension present: process
|
|
276
|
+
_, extension = os.path.splitext(src_path)
|
|
277
|
+
extension = extension[1:].lower()
|
|
278
|
+
|
|
279
|
+
if self._supported_extensions and extension not in self._supported_extensions:
|
|
280
|
+
return False
|
|
281
|
+
|
|
282
|
+
return True
|
|
283
|
+
|
|
255
284
|
# Regular expressions used to parse the diff output
|
|
256
285
|
SRC_FILE_RE = re.compile(r'^diff --git "?a/.*"? "?b/([^\n"]*)"?')
|
|
257
286
|
MERGE_CONFLICT_RE = re.compile(r"^diff --cc ([^\n]*)")
|
|
@@ -24,7 +24,7 @@ class XmlCoverageReporter(BaseViolationReporter):
|
|
|
24
24
|
Query information from a Cobertura|Clover|JaCoCo XML coverage report.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self, xml_roots, src_roots=None):
|
|
27
|
+
def __init__(self, xml_roots, src_roots=None, expand_coverage_report=False):
|
|
28
28
|
"""
|
|
29
29
|
Load the XML coverage report represented
|
|
30
30
|
by the cElementTree with root element `xml_root`.
|
|
@@ -41,6 +41,7 @@ class XmlCoverageReporter(BaseViolationReporter):
|
|
|
41
41
|
self._xml_cache = [{} for i in range(len(xml_roots))]
|
|
42
42
|
|
|
43
43
|
self._src_roots = src_roots or [""]
|
|
44
|
+
self._expand_coverage_report = expand_coverage_report
|
|
44
45
|
|
|
45
46
|
def _get_xml_classes(self, xml_document):
|
|
46
47
|
"""
|
|
@@ -216,6 +217,28 @@ class XmlCoverageReporter(BaseViolationReporter):
|
|
|
216
217
|
if line_nodes is None:
|
|
217
218
|
continue
|
|
218
219
|
|
|
220
|
+
# Expand coverage report with not reported lines
|
|
221
|
+
if self._expand_coverage_report:
|
|
222
|
+
reported_line_hits = {}
|
|
223
|
+
for line in line_nodes:
|
|
224
|
+
reported_line_hits[int(line.get(_number))] = int(
|
|
225
|
+
line.get(_hits, 0)
|
|
226
|
+
)
|
|
227
|
+
if reported_line_hits:
|
|
228
|
+
last_hit_number = 0
|
|
229
|
+
for line_number in range(
|
|
230
|
+
min(reported_line_hits.keys()),
|
|
231
|
+
max(reported_line_hits.keys()),
|
|
232
|
+
):
|
|
233
|
+
if line_number in reported_line_hits:
|
|
234
|
+
last_hit_number = reported_line_hits[line_number]
|
|
235
|
+
else:
|
|
236
|
+
# This is an unreported line.
|
|
237
|
+
# We add it with the previous line hit score
|
|
238
|
+
line_nodes.append(
|
|
239
|
+
{_hits: last_hit_number, _number: line_number}
|
|
240
|
+
)
|
|
241
|
+
|
|
219
242
|
# First case, need to define violations initially
|
|
220
243
|
if violations is None:
|
|
221
244
|
violations = {
|
|
@@ -264,7 +287,7 @@ class XmlCoverageReporter(BaseViolationReporter):
|
|
|
264
287
|
|
|
265
288
|
class LcovCoverageReporter(BaseViolationReporter):
|
|
266
289
|
"""
|
|
267
|
-
Query information from a
|
|
290
|
+
Query information from a LCov coverage report.
|
|
268
291
|
"""
|
|
269
292
|
|
|
270
293
|
def __init__(self, lcov_roots, src_roots=None):
|
|
@@ -324,6 +347,7 @@ class LcovCoverageReporter(BaseViolationReporter):
|
|
|
324
347
|
"BRF",
|
|
325
348
|
"BRH",
|
|
326
349
|
"BRDA",
|
|
350
|
+
"VER",
|
|
327
351
|
]:
|
|
328
352
|
# these are valid lines, but not we don't need them
|
|
329
353
|
continue
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "diff_cover"
|
|
3
|
-
version = "9.
|
|
3
|
+
version = "9.2.0"
|
|
4
4
|
description = "Run coverage and linting reports on diffs"
|
|
5
5
|
authors = ["See Contributors"]
|
|
6
6
|
homepage = "https://github.com/Bachmann1234/diff-cover"
|
|
@@ -55,10 +55,10 @@ pytest-mock = "^3.14.0"
|
|
|
55
55
|
pycodestyle = ">=2.9.1"
|
|
56
56
|
flake8 = "^5.0.4"
|
|
57
57
|
pyflakes = "^2.5.0"
|
|
58
|
-
pylint = "^3.2.
|
|
58
|
+
pylint = "^3.2.7"
|
|
59
59
|
pylint-pytest = "^1.1.8"
|
|
60
60
|
pydocstyle = "^6.1.1"
|
|
61
|
-
black = "^24.
|
|
61
|
+
black = "^24.8.0"
|
|
62
62
|
isort = "^5.13.2"
|
|
63
63
|
doc8 = "1.1.1"
|
|
64
64
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<!DOCTYPE coverage
|
|
3
|
+
SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>
|
|
4
|
+
<coverage branch-rate="0" line-rate="0.8792" timestamp="1371471706873" version="3.6">
|
|
5
|
+
<packages>
|
|
6
|
+
<package branch-rate="0" complexity="0" line-rate="0.9915" name="">
|
|
7
|
+
<classes>
|
|
8
|
+
<class branch-rate="0" complexity="0" filename="test_src.txt" line-rate="0.9643" name="test_src.txt">
|
|
9
|
+
<methods/>
|
|
10
|
+
<lines>
|
|
11
|
+
<line hits="1" number="1"/>
|
|
12
|
+
<line hits="0" number="2"/>
|
|
13
|
+
<line hits="0" number="4"/>
|
|
14
|
+
<line hits="1" number="5"/>
|
|
15
|
+
<line hits="1" number="7"/>
|
|
16
|
+
<line hits="0" number="8"/>
|
|
17
|
+
<line hits="1" number="9"/>
|
|
18
|
+
<line hits="0" number="10"/>
|
|
19
|
+
</lines>
|
|
20
|
+
</class>
|
|
21
|
+
</classes>
|
|
22
|
+
</package>
|
|
23
|
+
</packages>
|
|
24
|
+
</coverage>
|
|
@@ -618,16 +618,63 @@ def test_include_untracked(mocker, git_diff):
|
|
|
618
618
|
{"subdir/file1.py": line_numbers(3, 10) + line_numbers(34, 47)}
|
|
619
619
|
)
|
|
620
620
|
_set_git_diff_output(
|
|
621
|
-
reporter,
|
|
621
|
+
reporter,
|
|
622
|
+
git_diff,
|
|
623
|
+
staged_diff=diff_output,
|
|
624
|
+
untracked=["u1.py", " u2.py", "binary1.bin"],
|
|
622
625
|
)
|
|
623
626
|
|
|
624
|
-
|
|
625
|
-
|
|
627
|
+
base_open_mock = mocker.mock_open(read_data="1\n2\n3\n")
|
|
628
|
+
raise_count = 0
|
|
629
|
+
|
|
630
|
+
def open_side_effect(*args, **kwargs):
|
|
631
|
+
if args[0] == "binary1.bin":
|
|
632
|
+
nonlocal raise_count
|
|
633
|
+
raise_count += 1
|
|
634
|
+
|
|
635
|
+
raise UnicodeDecodeError("utf-8", b"", 0, 1, "invalid start byte")
|
|
636
|
+
return base_open_mock(*args, **kwargs)
|
|
637
|
+
|
|
638
|
+
mocker.patch("diff_cover.diff_reporter.open", open_side_effect)
|
|
626
639
|
changed = reporter.src_paths_changed()
|
|
627
640
|
|
|
628
|
-
assert sorted(changed) == [" u2.py", "subdir/file1.py", "u1.py"]
|
|
641
|
+
assert sorted(changed) == [" u2.py", "binary1.bin", "subdir/file1.py", "u1.py"]
|
|
629
642
|
assert reporter.lines_changed("u1.py") == [1, 2, 3]
|
|
630
643
|
assert reporter.lines_changed(" u2.py") == [1, 2, 3]
|
|
644
|
+
assert reporter.lines_changed("binary1.bin") == []
|
|
645
|
+
|
|
646
|
+
assert raise_count == 1
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
@pytest.mark.parametrize(
|
|
650
|
+
"excluded, supported_extensions, path",
|
|
651
|
+
[
|
|
652
|
+
(["file.bin"], ["py"], "file.bin"),
|
|
653
|
+
([], ["py"], "file.bin"),
|
|
654
|
+
],
|
|
655
|
+
)
|
|
656
|
+
def test_include_untracked__not_valid_path__not_include_it(
|
|
657
|
+
git_diff, excluded, supported_extensions, path
|
|
658
|
+
):
|
|
659
|
+
reporter = GitDiffReporter(
|
|
660
|
+
git_diff=git_diff,
|
|
661
|
+
include_untracked=True,
|
|
662
|
+
supported_extensions=supported_extensions,
|
|
663
|
+
exclude=excluded,
|
|
664
|
+
)
|
|
665
|
+
diff_output = git_diff_output(
|
|
666
|
+
{"subdir/file1.py": line_numbers(3, 10) + line_numbers(34, 47)}
|
|
667
|
+
)
|
|
668
|
+
_set_git_diff_output(
|
|
669
|
+
reporter,
|
|
670
|
+
git_diff,
|
|
671
|
+
staged_diff=diff_output,
|
|
672
|
+
untracked=[path],
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
changed = reporter.src_paths_changed()
|
|
676
|
+
|
|
677
|
+
assert sorted(changed) == ["subdir/file1.py"]
|
|
631
678
|
|
|
632
679
|
|
|
633
680
|
def _set_git_diff_output(
|
|
@@ -412,6 +412,20 @@ class TestDiffCoverIntegration(ToolsIntegrationBase):
|
|
|
412
412
|
["diff-cover", "--show-uncovered", "coverage.xml"],
|
|
413
413
|
)
|
|
414
414
|
|
|
415
|
+
def test_expand_coverage_report_complete_report(self):
|
|
416
|
+
self._check_console_report(
|
|
417
|
+
"git_diff_add.txt",
|
|
418
|
+
"add_console_report.txt",
|
|
419
|
+
["diff-cover", "coverage.xml", "--expand-coverage-report"],
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
def test_expand_coverage_report_uncomplete_report(self):
|
|
423
|
+
self._check_console_report(
|
|
424
|
+
"git_diff_add.txt",
|
|
425
|
+
"expand_console_report.txt",
|
|
426
|
+
["diff-cover", "coverage_missing_lines.xml", "--expand-coverage-report"],
|
|
427
|
+
)
|
|
428
|
+
|
|
415
429
|
|
|
416
430
|
class TestDiffQualityIntegration(ToolsIntegrationBase):
|
|
417
431
|
"""
|
|
@@ -66,6 +66,21 @@ class TestXmlCoverageReporterTest:
|
|
|
66
66
|
ONE_VIOLATION = {Violation(11, None)}
|
|
67
67
|
VERY_MANY_MEASURED = {2, 3, 5, 7, 11, 13, 17, 23, 24, 25, 26, 26, 27}
|
|
68
68
|
|
|
69
|
+
MANY_VIOLATIONS_EXPANDED_MANY_MEASURED = {
|
|
70
|
+
Violation(3, None),
|
|
71
|
+
Violation(4, None),
|
|
72
|
+
Violation(7, None),
|
|
73
|
+
Violation(8, None),
|
|
74
|
+
Violation(9, None),
|
|
75
|
+
Violation(10, None),
|
|
76
|
+
Violation(11, None),
|
|
77
|
+
Violation(12, None),
|
|
78
|
+
Violation(13, None),
|
|
79
|
+
Violation(14, None),
|
|
80
|
+
Violation(15, None),
|
|
81
|
+
Violation(16, None),
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
@pytest.fixture(autouse=True)
|
|
70
85
|
def patch_git_patch(self, mocker):
|
|
71
86
|
# Paths generated by git_path are always the given argument
|
|
@@ -266,6 +281,52 @@ class TestXmlCoverageReporterTest:
|
|
|
266
281
|
result = coverage.violations("file.py")
|
|
267
282
|
assert result == set()
|
|
268
283
|
|
|
284
|
+
def test_expand_unreported_lines_when_configured(self):
|
|
285
|
+
# Construct the XML report
|
|
286
|
+
file_paths = ["file1.java"]
|
|
287
|
+
# fixture
|
|
288
|
+
violations = self.MANY_VIOLATIONS
|
|
289
|
+
measured = self.MANY_MEASURED
|
|
290
|
+
xml = self._coverage_xml(file_paths, violations, measured)
|
|
291
|
+
|
|
292
|
+
# Parse the reports
|
|
293
|
+
coverage = XmlCoverageReporter([xml], expand_coverage_report=True)
|
|
294
|
+
|
|
295
|
+
# Expect that the name is set
|
|
296
|
+
assert coverage.name() == "XML"
|
|
297
|
+
|
|
298
|
+
# By construction, each file has the same set
|
|
299
|
+
# of covered/uncovered lines
|
|
300
|
+
assert self.MANY_VIOLATIONS_EXPANDED_MANY_MEASURED == coverage.violations(
|
|
301
|
+
"file1.java"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def test_expand_unreported_lines_without_violations(self):
|
|
305
|
+
# Construct the XML report
|
|
306
|
+
file_paths = ["file1.java"]
|
|
307
|
+
# fixture
|
|
308
|
+
violations = {}
|
|
309
|
+
measured = self.MANY_MEASURED
|
|
310
|
+
xml = self._coverage_xml(file_paths, violations, measured)
|
|
311
|
+
|
|
312
|
+
# Parse the reports
|
|
313
|
+
coverage = XmlCoverageReporter([xml], expand_coverage_report=True)
|
|
314
|
+
|
|
315
|
+
assert set() == coverage.violations("file1.java")
|
|
316
|
+
|
|
317
|
+
def test_expand_unreported_lines_without_measured(self):
|
|
318
|
+
# Construct the XML report
|
|
319
|
+
file_paths = ["file1.java"]
|
|
320
|
+
# fixture
|
|
321
|
+
violations = {}
|
|
322
|
+
measured = {}
|
|
323
|
+
xml = self._coverage_xml(file_paths, violations, measured)
|
|
324
|
+
|
|
325
|
+
# Parse the reports
|
|
326
|
+
coverage = XmlCoverageReporter([xml], expand_coverage_report=True)
|
|
327
|
+
|
|
328
|
+
assert set() == coverage.violations("file1.java")
|
|
329
|
+
|
|
269
330
|
def _coverage_xml(self, file_paths, violations, measured, source_paths=None):
|
|
270
331
|
"""
|
|
271
332
|
Build an XML tree with source files specified by `file_paths`.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{diff_cover-9.1.0 → diff_cover-9.2.0}/diff_cover/violationsreporters/java_violations_reporter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{diff_cover-9.1.0 → diff_cover-9.2.0}/tests/fixtures/pycodestyle_violations_report_external_css.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|