Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1095,4 +1095,10 @@ def samefile_nofollow(p1: Path, p2: Path) -> bool:

Unlike Path.samefile(), does not resolve symlinks.
"""
return os.path.samestat(p1.lstat(), p2.lstat())
s1, s2 = p1.lstat(), p2.lstat()
# Some network filesystems report a zero inode for every path. In that
# case samestat() cannot distinguish different files and would make every
# collected path match the requested one.
if not s1.st_ino or not s2.st_ino:
return False
return os.path.samestat(s1, s2)
15 changes: 15 additions & 0 deletions testing/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from _pytest.pathlib import resolve_package_path
from _pytest.pathlib import resolve_pkg_root_and_module_name
from _pytest.pathlib import safe_exists
from _pytest.pathlib import samefile_nofollow
from _pytest.pathlib import scandir
from _pytest.pathlib import spec_matches_module_path
from _pytest.pathlib import symlink_or_skip
Expand Down Expand Up @@ -570,6 +571,20 @@ def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> N
assert getattr(module, "foo")() == 42


@pytest.mark.parametrize("inodes", [(0, 0), (0, 1), (1, 0)])
def test_samefile_nofollow_rejects_zero_inodes(
inodes: tuple[int, int], monkeypatch: MonkeyPatch
) -> None:
stats = [unittest.mock.Mock(st_ino=inode) for inode in inodes]
lstat = unittest.mock.Mock(side_effect=stats)
samestat = unittest.mock.Mock(return_value=True)
monkeypatch.setattr(Path, "lstat", lstat)
monkeypatch.setattr(os.path, "samestat", samestat)

assert not samefile_nofollow(Path("first"), Path("second"))
samestat.assert_not_called()


def test_scandir_with_non_existent_directory() -> None:
# Test with a directory that does not exist
non_existent_dir = "path_to_non_existent_dir"
Expand Down