Skip to content

GH-112675: Move path joining tests into test_posixpath and test_ntpath #112676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 7, 2023
Merged
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
11 changes: 11 additions & 0 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ def test_join(self):
tester('ntpath.join("a", "b", "c")', 'a\\b\\c')
tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c')
tester('ntpath.join("a", "b\\", "c")', 'a\\b\\c')
tester('ntpath.join("a", "b", "c\\")', 'a\\b\\c\\')
tester('ntpath.join("a", "b", "\\c")', '\\c')
tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep')
tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b')
Expand Down Expand Up @@ -313,6 +314,16 @@ def test_join(self):
tester("ntpath.join('\\\\computer\\', 'share')", '\\\\computer\\share')
tester("ntpath.join('\\\\computer\\share\\', 'a')", '\\\\computer\\share\\a')
tester("ntpath.join('\\\\computer\\share\\a\\', 'b')", '\\\\computer\\share\\a\\b')
# Second part is anchored, so that the first part is ignored.
tester("ntpath.join('a', 'Z:b', 'c')", 'Z:b\\c')
tester("ntpath.join('a', 'Z:\\b', 'c')", 'Z:\\b\\c')
tester("ntpath.join('a', '\\\\b\\c', 'd')", '\\\\b\\c\\d')
# Second part has a root but not drive.
tester("ntpath.join('a', '\\b', 'c')", '\\b\\c')
tester("ntpath.join('Z:/a', '/b', 'c')", 'Z:\\b\\c')
tester("ntpath.join('//?/Z:/a', '/b', 'c')", '\\\\?\\Z:\\b\\c')
tester("ntpath.join('D:a', './c:b')", 'D:a\\.\\c:b')
tester("ntpath.join('D:/a', './c:b')", 'D:\\a\\.\\c:b')

def test_normpath(self):
tester("ntpath.normpath('A//////././//.//B')", r'A\B')
Expand Down
159 changes: 65 additions & 94 deletions Lib/test/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,45 +157,30 @@ def with_segments(self, *pathsegments):
for parent in p.parents:
self.assertEqual(42, parent.session_id)

def _get_drive_root_parts(self, parts):
path = self.cls(*parts)
return path.drive, path.root, path.parts

def _check_drive_root_parts(self, arg, *expected):
def _check_parse_path(self, raw_path, *expected):
sep = self.pathmod.sep
actual = self._get_drive_root_parts([x.replace('/', sep) for x in arg])
actual = self.cls._parse_path(raw_path.replace('/', sep))
self.assertEqual(actual, expected)
if altsep := self.pathmod.altsep:
actual = self._get_drive_root_parts([x.replace('/', altsep) for x in arg])
actual = self.cls._parse_path(raw_path.replace('/', altsep))
self.assertEqual(actual, expected)

def test_drive_root_parts_common(self):
check = self._check_drive_root_parts
def test_parse_path_common(self):
check = self._check_parse_path
sep = self.pathmod.sep
# Unanchored parts.
check((), '', '', ())
check(('a',), '', '', ('a',))
check(('a/',), '', '', ('a',))
check(('a', 'b'), '', '', ('a', 'b'))
# Expansion.
check(('a/b',), '', '', ('a', 'b'))
check(('a/b/',), '', '', ('a', 'b'))
check(('a', 'b/c', 'd'), '', '', ('a', 'b', 'c', 'd'))
# Collapsing and stripping excess slashes.
check(('a', 'b//c', 'd'), '', '', ('a', 'b', 'c', 'd'))
check(('a', 'b/c/', 'd'), '', '', ('a', 'b', 'c', 'd'))
# Eliminating standalone dots.
check(('.',), '', '', ())
check(('.', '.', 'b'), '', '', ('b',))
check(('a', '.', 'b'), '', '', ('a', 'b'))
check(('a', '.', '.'), '', '', ('a',))
# The first part is anchored.
check(('/a/b',), '', sep, (sep, 'a', 'b'))
check(('/a', 'b'), '', sep, (sep, 'a', 'b'))
check(('/a/', 'b'), '', sep, (sep, 'a', 'b'))
# Ignoring parts before an anchored part.
check(('a', '/b', 'c'), '', sep, (sep, 'b', 'c'))
check(('a', '/b', '/c'), '', sep, (sep, 'c'))
check('', '', '', [])
check('a', '', '', ['a'])
check('a/', '', '', ['a'])
check('a/b', '', '', ['a', 'b'])
check('a/b/', '', '', ['a', 'b'])
check('a/b/c/d', '', '', ['a', 'b', 'c', 'd'])
check('a/b//c/d', '', '', ['a', 'b', 'c', 'd'])
check('a/b/c/d', '', '', ['a', 'b', 'c', 'd'])
check('.', '', '', [])
check('././b', '', '', ['b'])
check('a/./b', '', '', ['a', 'b'])
check('a/./.', '', '', ['a'])
check('/a/b', '', sep, ['a', 'b'])

def test_join_common(self):
P = self.cls
Expand Down Expand Up @@ -789,17 +774,17 @@ def test_repr_roundtrips(self):
class PurePosixPathTest(PurePathTest):
cls = pathlib.PurePosixPath

def test_drive_root_parts(self):
check = self._check_drive_root_parts
def test_parse_path(self):
check = self._check_parse_path
# Collapsing of excess leading slashes, except for the double-slash
# special case.
check(('//a', 'b'), '', '//', ('//', 'a', 'b'))
check(('///a', 'b'), '', '/', ('/', 'a', 'b'))
check(('////a', 'b'), '', '/', ('/', 'a', 'b'))
check('//a/b', '', '//', ['a', 'b'])
check('///a/b', '', '/', ['a', 'b'])
check('////a/b', '', '/', ['a', 'b'])
# Paths which look like NT paths aren't treated specially.
check(('c:a',), '', '', ('c:a',))
check(('c:\\a',), '', '', ('c:\\a',))
check(('\\a',), '', '', ('\\a',))
check('c:a', '', '', ['c:a',])
check('c:\\a', '', '', ['c:\\a',])
check('\\a', '', '', ['\\a',])

def test_root(self):
P = self.cls
Expand Down Expand Up @@ -897,67 +882,53 @@ class PureWindowsPathTest(PurePathTest):
],
})

def test_drive_root_parts(self):
check = self._check_drive_root_parts
def test_parse_path(self):
check = self._check_parse_path
# First part is anchored.
check(('c:',), 'c:', '', ('c:',))
check(('c:/',), 'c:', '\\', ('c:\\',))
check(('/',), '', '\\', ('\\',))
check(('c:a',), 'c:', '', ('c:', 'a'))
check(('c:/a',), 'c:', '\\', ('c:\\', 'a'))
check(('/a',), '', '\\', ('\\', 'a'))
# UNC paths.
check(('//',), '\\\\', '', ('\\\\',))
check(('//a',), '\\\\a', '', ('\\\\a',))
check(('//a/',), '\\\\a\\', '', ('\\\\a\\',))
check(('//a/b',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
check(('//a/b/',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
check(('//a/b/c',), '\\\\a\\b', '\\', ('\\\\a\\b\\', 'c'))
# Second part is anchored, so that the first part is ignored.
check(('a', 'Z:b', 'c'), 'Z:', '', ('Z:', 'b', 'c'))
check(('a', 'Z:/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c'))
check('c:', 'c:', '', [])
check('c:/', 'c:', '\\', [])
check('/', '', '\\', [])
check('c:a', 'c:', '', ['a'])
check('c:/a', 'c:', '\\', ['a'])
check('/a', '', '\\', ['a'])
# UNC paths.
check(('a', '//b/c', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd'))
check('//', '\\\\', '', [])
check('//a', '\\\\a', '', [])
check('//a/', '\\\\a\\', '', [])
check('//a/b', '\\\\a\\b', '\\', [])
check('//a/b/', '\\\\a\\b', '\\', [])
check('//a/b/c', '\\\\a\\b', '\\', ['c'])
# Collapsing and stripping excess slashes.
check(('a', 'Z://b//c/', 'd/'), 'Z:', '\\', ('Z:\\', 'b', 'c', 'd'))
check('Z://b//c/d/', 'Z:', '\\', ['b', 'c', 'd'])
# UNC paths.
check(('a', '//b/c//', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd'))
check('//b/c//d', '\\\\b\\c', '\\', ['d'])
# Extended paths.
check(('//./c:',), '\\\\.\\c:', '', ('\\\\.\\c:',))
check(('//?/c:/',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\',))
check(('//?/c:/a',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'a'))
check(('//?/c:/a', '/b'), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'b'))
check('//./c:', '\\\\.\\c:', '', [])
check('//?/c:/', '\\\\?\\c:', '\\', [])
check('//?/c:/a', '\\\\?\\c:', '\\', ['a'])
# Extended UNC paths (format is "\\?\UNC\server\share").
check(('//?',), '\\\\?', '', ('\\\\?',))
check(('//?/',), '\\\\?\\', '', ('\\\\?\\',))
check(('//?/UNC',), '\\\\?\\UNC', '', ('\\\\?\\UNC',))
check(('//?/UNC/',), '\\\\?\\UNC\\', '', ('\\\\?\\UNC\\',))
check(('//?/UNC/b',), '\\\\?\\UNC\\b', '', ('\\\\?\\UNC\\b',))
check(('//?/UNC/b/',), '\\\\?\\UNC\\b\\', '', ('\\\\?\\UNC\\b\\',))
check(('//?/UNC/b/c',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
check(('//?/UNC/b/c/',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
check(('//?/UNC/b/c/d',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\', 'd'))
check('//?', '\\\\?', '', [])
check('//?/', '\\\\?\\', '', [])
check('//?/UNC', '\\\\?\\UNC', '', [])
check('//?/UNC/', '\\\\?\\UNC\\', '', [])
check('//?/UNC/b', '\\\\?\\UNC\\b', '', [])
check('//?/UNC/b/', '\\\\?\\UNC\\b\\', '', [])
check('//?/UNC/b/c', '\\\\?\\UNC\\b\\c', '\\', [])
check('//?/UNC/b/c/', '\\\\?\\UNC\\b\\c', '\\', [])
check('//?/UNC/b/c/d', '\\\\?\\UNC\\b\\c', '\\', ['d'])
# UNC device paths
check(('//./BootPartition/',), '\\\\.\\BootPartition', '\\', ('\\\\.\\BootPartition\\',))
check(('//?/BootPartition/',), '\\\\?\\BootPartition', '\\', ('\\\\?\\BootPartition\\',))
check(('//./PhysicalDrive0',), '\\\\.\\PhysicalDrive0', '', ('\\\\.\\PhysicalDrive0',))
check(('//?/Volume{}/',), '\\\\?\\Volume{}', '\\', ('\\\\?\\Volume{}\\',))
check(('//./nul',), '\\\\.\\nul', '', ('\\\\.\\nul',))
# Second part has a root but not drive.
check(('a', '/b', 'c'), '', '\\', ('\\', 'b', 'c'))
check(('Z:/a', '/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c'))
check(('//?/Z:/a', '/b', 'c'), '\\\\?\\Z:', '\\', ('\\\\?\\Z:\\', 'b', 'c'))
# Joining with the same drive => the first path is appended to if
# the second path is relative.
check(('c:/a/b', 'c:x/y'), 'c:', '\\', ('c:\\', 'a', 'b', 'x', 'y'))
check(('c:/a/b', 'c:/x/y'), 'c:', '\\', ('c:\\', 'x', 'y'))
check('//./BootPartition/', '\\\\.\\BootPartition', '\\', [])
check('//?/BootPartition/', '\\\\?\\BootPartition', '\\', [])
check('//./PhysicalDrive0', '\\\\.\\PhysicalDrive0', '', [])
check('//?/Volume{}/', '\\\\?\\Volume{}', '\\', [])
check('//./nul', '\\\\.\\nul', '', [])
# Paths to files with NTFS alternate data streams
check(('./c:s',), '', '', ('c:s',))
check(('cc:s',), '', '', ('cc:s',))
check(('C:c:s',), 'C:', '', ('C:', 'c:s'))
check(('C:/c:s',), 'C:', '\\', ('C:\\', 'c:s'))
check(('D:a', './c:b'), 'D:', '', ('D:', 'a', 'c:b'))
check(('D:/a', './c:b'), 'D:', '\\', ('D:\\', 'a', 'c:b'))
check('./c:s', '', '', ['c:s'])
check('cc:s', '', '', ['cc:s'])
check('C:c:s', 'C:', '', ['c:s'])
check('C:/c:s', 'C:', '\\', ['c:s'])
check('D:a/c:b', 'D:', '', ['a', 'c:b'])
check('D:/a/c:b', 'D:', '\\', ['a', 'c:b'])

def test_str(self):
p = self.cls('a/b/c')
Expand Down
32 changes: 20 additions & 12 deletions Lib/test/test_posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,26 @@ def tearDown(self):
safe_rmdir(os_helper.TESTFN + suffix)

def test_join(self):
self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"),
"/bar/baz")
self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"),
"/foo/bar/baz/")

self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"),
b"/bar/baz")
self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"),
b"/foo/bar/baz")
self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"),
b"/foo/bar/baz/")
fn = posixpath.join
self.assertEqual(fn("/foo", "bar", "/bar", "baz"), "/bar/baz")
self.assertEqual(fn("/foo", "bar", "baz"), "/foo/bar/baz")
self.assertEqual(fn("/foo/", "bar/", "baz/"), "/foo/bar/baz/")

self.assertEqual(fn(b"/foo", b"bar", b"/bar", b"baz"), b"/bar/baz")
self.assertEqual(fn(b"/foo", b"bar", b"baz"), b"/foo/bar/baz")
self.assertEqual(fn(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/")

self.assertEqual(fn("a", "b"), "a/b")
self.assertEqual(fn("a", "b/"), "a/b/")
self.assertEqual(fn("a/", "b"), "a/b")
self.assertEqual(fn("a/", "b/"), "a/b/")
self.assertEqual(fn("a", "b/c", "d"), "a/b/c/d")
self.assertEqual(fn("a", "b//c", "d"), "a/b//c/d")
self.assertEqual(fn("a", "b/c/", "d"), "a/b/c/d")
self.assertEqual(fn("/a", "b"), "/a/b")
self.assertEqual(fn("/a/", "b"), "/a/b")
self.assertEqual(fn("a", "/b", "c"), "/b/c")
self.assertEqual(fn("a", "/b", "/c"), "/c")

def test_split(self):
self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
Expand Down