summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/control.py18
-rw-r--r--coverage/files.py14
-rw-r--r--coverage/sqldata.py4
-rw-r--r--tests/test_files.py20
4 files changed, 45 insertions, 11 deletions
diff --git a/coverage/control.py b/coverage/control.py
index 5e1e54bf..91e604e0 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -741,16 +741,14 @@ class Coverage:
self._post_init()
self.get_data()
- aliases = None
- if self.config.paths:
- aliases = PathAliases(
- debugfn=(self._debug.write if self._debug.should("pathmap") else None),
- relative=self.config.relative_files,
- )
- for paths in self.config.paths.values():
- result = paths[0]
- for pattern in paths[1:]:
- aliases.add(pattern, result)
+ aliases = PathAliases(
+ debugfn=(self._debug.write if self._debug.should("pathmap") else None),
+ relative=self.config.relative_files,
+ )
+ for paths in self.config.paths.values():
+ result = paths[0]
+ for pattern in paths[1:]:
+ aliases.add(pattern, result)
combine_parallel_data(
self._data,
diff --git a/coverage/files.py b/coverage/files.py
index 87a18bc2..2c520b8a 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -409,6 +409,20 @@ class PathAliases:
f"producing {new!r}"
)
return new
+
+ # If we get here, no pattern matched.
+
+ if self.relative and not isabs_anywhere(path):
+ parts = re.split(r"[/\\]", path)
+ if len(parts) > 1:
+ dir1 = parts[0]
+ pattern = f"*/{dir1}"
+ regex = rf"^(.*[\\/])?{re.escape(dir1)}[\\/]"
+ result = f"{dir1}{os.sep}"
+ self.debugfn(f"Generating rule: {pattern!r} -> {result!r} using regex {regex!r}")
+ self.aliases.append((pattern, re.compile(regex), result))
+ return self.map(path)
+
self.debugfn(f"No rules match, path {path!r} is unchanged")
return path
diff --git a/coverage/sqldata.py b/coverage/sqldata.py
index 5d62b15b..5d7fbecf 100644
--- a/coverage/sqldata.py
+++ b/coverage/sqldata.py
@@ -596,7 +596,9 @@ class CoverageData(SimpleReprMixin):
"""Update this data with data from several other :class:`CoverageData` instances.
If `aliases` is provided, it's a `PathAliases` object that is used to
- re-map paths to match the local machine's.
+ re-map paths to match the local machine's. Note: `aliases` is None
+ only when called directly from the test suite.
+
"""
if self._debug.should("dataop"):
self._debug.write("Updating with data from {!r}".format(
diff --git a/tests/test_files.py b/tests/test_files.py
index 8ce2d5f7..8fea61d0 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -416,6 +416,26 @@ class PathAliasesTest(CoverageTest):
r"project\module\tests\file.py",
)
+ @pytest.mark.skipif(env.WINDOWS, reason="This test assumes Unix file system")
+ def test_implicit_relative_windows_on_linux(self):
+ # https://github.com/nedbat/coveragepy/issues/991
+ aliases = PathAliases(relative=True)
+ self.assert_mapped(
+ aliases,
+ r"project\module\tests\file.py",
+ r"project/module/tests/file.py",
+ )
+
+ @pytest.mark.skipif(not env.WINDOWS, reason="This test assumes Windows file system")
+ def test_implicit_relative_linux_on_windows(self):
+ # https://github.com/nedbat/coveragepy/issues/991
+ aliases = PathAliases(relative=True)
+ self.assert_mapped(
+ aliases,
+ r"project/module/tests/file.py",
+ r"project\module\tests\file.py",
+ )
+
def test_multiple_wildcard(self, rel_yn):
aliases = PathAliases(relative=rel_yn)
aliases.add('/home/jenkins/*/a/*/b/*/django', './django')