Skip to content

Commit 1b19799

Browse files
committed
fix: ensure absolute paths are relative when combined #1752
If two data files are combined, one with absolute paths, and one with relative, with relative_files=True in effect, the results depended on the order of combining. If the absolute files were seen first, they were added as absolute paths. If the relative files were seen first, a mapping rule was generated that would then remap the absolute paths when they were seen. This fix ensures that absolute paths are remapped even if they are seen first.
1 parent 1ef020d commit 1b19799

File tree

4 files changed

+35
-1
lines changed

4 files changed

+35
-1
lines changed

CHANGES.rst

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ upgrading your version of coverage.py.
2323
Unreleased
2424
----------
2525

26+
- Fix: in some cases, even with ``[run] relative_files=True``, a data file
27+
could be created with absolute path names. When combined with other relative
28+
data files, it was random whether the absolute file names would be made
29+
relative or not. If they weren't, then a file would be listed twice in
30+
reports, as detailed in `issue 1752`_. This is now fixed: absolute file
31+
names are always made relative when combining.
32+
2633
- Fix: the last case of a match/case statement had an incorrect message if the
2734
branch was missed. It said the pattern never matched, when actually the
2835
branch is missed if the last case always matched.
@@ -33,6 +40,7 @@ Unreleased
3340
string. Thanks, `Tanaydin Sirin <pull 1754_>`_. It is also now documented
3441
on the :ref:`configuration page <config_report_format>`.
3542

43+
.. _issue 1752: https://github.com/nedbat/coveragepy/issues/1752
3644
.. _pull 1754: https://github.com/nedbat/coveragepy/pull/1754
3745

3846

coverage/data.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ def combinable_files(data_file: str, data_paths: Iterable[str] | None = None) ->
8888
# We never want to combine those.
8989
files_to_combine = [fnm for fnm in files_to_combine if not fnm.endswith("-journal")]
9090

91-
return files_to_combine
91+
# Sorting isn't usually needed, since it shouldn't matter what order files
92+
# are combined, but sorting makes tests more predictable, and makes
93+
# debugging more understandable when things go wrong.
94+
return sorted(files_to_combine)
9295

9396

9497
def combine_parallel_data(

coverage/files.py

+3
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ def map(self, path: str, exists:Callable[[str], bool] = source_exists) -> str:
489489

490490
# If we get here, no pattern matched.
491491

492+
if self.relative:
493+
path = relative_filename(path)
494+
492495
if self.relative and not isabs_anywhere(path):
493496
# Auto-generate a pattern to implicitly match relative files
494497
parts = re.split(r"[/\\]", path)

tests/test_api.py

+20
Original file line numberDiff line numberDiff line change
@@ -1465,3 +1465,23 @@ def test_combine_parallel_data_keep(self) -> None:
14651465
# After combining, the .coverage file & the original combined file should still be there.
14661466
self.assert_exists(".coverage")
14671467
self.assert_file_count(".coverage.*", 2)
1468+
1469+
@pytest.mark.parametrize("abs_order, rel_order", [(1, 2), (2, 1)])
1470+
def test_combine_absolute_then_relative_1752(self, abs_order: int, rel_order: int) -> None:
1471+
# https://github.com/nedbat/coveragepy/issues/1752
1472+
# If we're combining a relative data file and an absolute data file,
1473+
# the absolutes were made relative only if the relative file name was
1474+
# encountered first. Test combining in both orders and check that the
1475+
# absolute file name is properly relative in either order.
1476+
FILE = "sub/myprog.py"
1477+
self.make_file(FILE, "a = 1")
1478+
1479+
self.make_data_file(suffix=f"{abs_order}.abs", lines={abs_file(FILE): [1]})
1480+
self.make_data_file(suffix=f"{rel_order}.rel", lines={FILE: [1]})
1481+
1482+
self.make_file(".coveragerc", "[run]\nrelative_files = True\n")
1483+
cov = coverage.Coverage()
1484+
cov.combine()
1485+
data = coverage.CoverageData()
1486+
data.read()
1487+
assert {os_sep("sub/myprog.py")} == data.measured_files()

0 commit comments

Comments
 (0)