1import inspect 2import ntpath 3import os 4import string 5import subprocess 6import sys 7import unittest 8import warnings 9from test.support import cpython_only, os_helper 10from test.support import TestFailed, is_emscripten 11from test.support.os_helper import FakePath 12from test import test_genericpath 13from tempfile import TemporaryFile 14 15 16try: 17 import nt 18except ImportError: 19 # Most tests can complete without the nt module, 20 # but for those that require it we import here. 21 nt = None 22 23try: 24 ntpath._getfinalpathname 25except AttributeError: 26 HAVE_GETFINALPATHNAME = False 27else: 28 HAVE_GETFINALPATHNAME = True 29 30try: 31 import ctypes 32except ImportError: 33 HAVE_GETSHORTPATHNAME = False 34else: 35 HAVE_GETSHORTPATHNAME = True 36 def _getshortpathname(path): 37 GSPN = ctypes.WinDLL("kernel32", use_last_error=True).GetShortPathNameW 38 GSPN.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32] 39 GSPN.restype = ctypes.c_uint32 40 result_len = GSPN(path, None, 0) 41 if not result_len: 42 raise OSError("failed to get short path name 0x{:08X}" 43 .format(ctypes.get_last_error())) 44 result = ctypes.create_unicode_buffer(result_len) 45 result_len = GSPN(path, result, result_len) 46 return result[:result_len] 47 48def _norm(path): 49 if isinstance(path, (bytes, str, os.PathLike)): 50 return ntpath.normcase(os.fsdecode(path)) 51 elif hasattr(path, "__iter__"): 52 return tuple(ntpath.normcase(os.fsdecode(p)) for p in path) 53 return path 54 55 56def tester(fn, wantResult): 57 fn = fn.replace("\\", "\\\\") 58 gotResult = eval(fn) 59 if wantResult != gotResult and _norm(wantResult) != _norm(gotResult): 60 raise TestFailed("%s should return: %s but returned: %s" \ 61 %(str(fn), str(wantResult), str(gotResult))) 62 63 # then with bytes 64 fn = fn.replace("('", "(b'") 65 fn = fn.replace('("', '(b"') 66 fn = fn.replace("['", "[b'") 67 fn = fn.replace('["', '[b"') 68 fn = fn.replace(", '", ", b'") 69 fn = fn.replace(', "', ', b"') 70 fn = os.fsencode(fn).decode('latin1') 71 fn = fn.encode('ascii', 'backslashreplace').decode('ascii') 72 with warnings.catch_warnings(): 73 warnings.simplefilter("ignore", DeprecationWarning) 74 gotResult = eval(fn) 75 if _norm(wantResult) != _norm(gotResult): 76 raise TestFailed("%s should return: %s but returned: %s" \ 77 %(str(fn), str(wantResult), repr(gotResult))) 78 79 80class NtpathTestCase(unittest.TestCase): 81 def assertPathEqual(self, path1, path2): 82 if path1 == path2 or _norm(path1) == _norm(path2): 83 return 84 self.assertEqual(path1, path2) 85 86 def assertPathIn(self, path, pathset): 87 self.assertIn(_norm(path), _norm(pathset)) 88 89 90class TestNtpath(NtpathTestCase): 91 def test_splitext(self): 92 tester('ntpath.splitext("foo.ext")', ('foo', '.ext')) 93 tester('ntpath.splitext("/foo/foo.ext")', ('/foo/foo', '.ext')) 94 tester('ntpath.splitext(".ext")', ('.ext', '')) 95 tester('ntpath.splitext("\\foo.ext\\foo")', ('\\foo.ext\\foo', '')) 96 tester('ntpath.splitext("foo.ext\\")', ('foo.ext\\', '')) 97 tester('ntpath.splitext("")', ('', '')) 98 tester('ntpath.splitext("foo.bar.ext")', ('foo.bar', '.ext')) 99 tester('ntpath.splitext("xx/foo.bar.ext")', ('xx/foo.bar', '.ext')) 100 tester('ntpath.splitext("xx\\foo.bar.ext")', ('xx\\foo.bar', '.ext')) 101 tester('ntpath.splitext("c:a/b\\c.d")', ('c:a/b\\c', '.d')) 102 103 def test_splitdrive(self): 104 tester("ntpath.splitdrive('')", ('', '')) 105 tester("ntpath.splitdrive('foo')", ('', 'foo')) 106 tester("ntpath.splitdrive('foo\\bar')", ('', 'foo\\bar')) 107 tester("ntpath.splitdrive('foo/bar')", ('', 'foo/bar')) 108 tester("ntpath.splitdrive('\\')", ('', '\\')) 109 tester("ntpath.splitdrive('/')", ('', '/')) 110 tester("ntpath.splitdrive('\\foo\\bar')", ('', '\\foo\\bar')) 111 tester("ntpath.splitdrive('/foo/bar')", ('', '/foo/bar')) 112 tester('ntpath.splitdrive("c:foo\\bar")', ('c:', 'foo\\bar')) 113 tester('ntpath.splitdrive("c:foo/bar")', ('c:', 'foo/bar')) 114 tester('ntpath.splitdrive("c:\\foo\\bar")', ('c:', '\\foo\\bar')) 115 tester('ntpath.splitdrive("c:/foo/bar")', ('c:', '/foo/bar')) 116 tester("ntpath.splitdrive('\\\\')", ('\\\\', '')) 117 tester("ntpath.splitdrive('//')", ('//', '')) 118 tester('ntpath.splitdrive("\\\\conky\\mountpoint\\foo\\bar")', 119 ('\\\\conky\\mountpoint', '\\foo\\bar')) 120 tester('ntpath.splitdrive("//conky/mountpoint/foo/bar")', 121 ('//conky/mountpoint', '/foo/bar')) 122 tester('ntpath.splitdrive("\\\\?\\UNC\\server\\share\\dir")', 123 ("\\\\?\\UNC\\server\\share", "\\dir")) 124 tester('ntpath.splitdrive("//?/UNC/server/share/dir")', 125 ("//?/UNC/server/share", "/dir")) 126 127 def test_splitroot(self): 128 tester("ntpath.splitroot('')", ('', '', '')) 129 tester("ntpath.splitroot('foo')", ('', '', 'foo')) 130 tester("ntpath.splitroot('foo\\bar')", ('', '', 'foo\\bar')) 131 tester("ntpath.splitroot('foo/bar')", ('', '', 'foo/bar')) 132 tester("ntpath.splitroot('\\')", ('', '\\', '')) 133 tester("ntpath.splitroot('/')", ('', '/', '')) 134 tester("ntpath.splitroot('\\foo\\bar')", ('', '\\', 'foo\\bar')) 135 tester("ntpath.splitroot('/foo/bar')", ('', '/', 'foo/bar')) 136 tester('ntpath.splitroot("c:foo\\bar")', ('c:', '', 'foo\\bar')) 137 tester('ntpath.splitroot("c:foo/bar")', ('c:', '', 'foo/bar')) 138 tester('ntpath.splitroot("c:\\foo\\bar")', ('c:', '\\', 'foo\\bar')) 139 tester('ntpath.splitroot("c:/foo/bar")', ('c:', '/', 'foo/bar')) 140 141 # Redundant slashes are not included in the root. 142 tester("ntpath.splitroot('c:\\\\a')", ('c:', '\\', '\\a')) 143 tester("ntpath.splitroot('c:\\\\\\a/b')", ('c:', '\\', '\\\\a/b')) 144 145 # Mixed path separators. 146 tester("ntpath.splitroot('c:/\\')", ('c:', '/', '\\')) 147 tester("ntpath.splitroot('c:\\/')", ('c:', '\\', '/')) 148 tester("ntpath.splitroot('/\\a/b\\/\\')", ('/\\a/b', '\\', '/\\')) 149 tester("ntpath.splitroot('\\/a\\b/\\/')", ('\\/a\\b', '/', '\\/')) 150 151 # UNC paths. 152 tester("ntpath.splitroot('\\\\')", ('\\\\', '', '')) 153 tester("ntpath.splitroot('//')", ('//', '', '')) 154 tester('ntpath.splitroot("\\\\conky\\mountpoint\\foo\\bar")', 155 ('\\\\conky\\mountpoint', '\\', 'foo\\bar')) 156 tester('ntpath.splitroot("//conky/mountpoint/foo/bar")', 157 ('//conky/mountpoint', '/', 'foo/bar')) 158 tester('ntpath.splitroot("\\\\\\conky\\mountpoint\\foo\\bar")', 159 ('\\\\\\conky', '\\', 'mountpoint\\foo\\bar')) 160 tester('ntpath.splitroot("///conky/mountpoint/foo/bar")', 161 ('///conky', '/', 'mountpoint/foo/bar')) 162 tester('ntpath.splitroot("\\\\conky\\\\mountpoint\\foo\\bar")', 163 ('\\\\conky\\', '\\', 'mountpoint\\foo\\bar')) 164 tester('ntpath.splitroot("//conky//mountpoint/foo/bar")', 165 ('//conky/', '/', 'mountpoint/foo/bar')) 166 167 # Issue #19911: UNC part containing U+0130 168 self.assertEqual(ntpath.splitroot('//conky/MOUNTPOİNT/foo/bar'), 169 ('//conky/MOUNTPOİNT', '/', 'foo/bar')) 170 171 # gh-81790: support device namespace, including UNC drives. 172 tester('ntpath.splitroot("//?/c:")', ("//?/c:", "", "")) 173 tester('ntpath.splitroot("//./c:")', ("//./c:", "", "")) 174 tester('ntpath.splitroot("//?/c:/")', ("//?/c:", "/", "")) 175 tester('ntpath.splitroot("//?/c:/dir")', ("//?/c:", "/", "dir")) 176 tester('ntpath.splitroot("//?/UNC")', ("//?/UNC", "", "")) 177 tester('ntpath.splitroot("//?/UNC/")', ("//?/UNC/", "", "")) 178 tester('ntpath.splitroot("//?/UNC/server/")', ("//?/UNC/server/", "", "")) 179 tester('ntpath.splitroot("//?/UNC/server/share")', ("//?/UNC/server/share", "", "")) 180 tester('ntpath.splitroot("//?/UNC/server/share/dir")', ("//?/UNC/server/share", "/", "dir")) 181 tester('ntpath.splitroot("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")', 182 ('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/', 'spam')) 183 tester('ntpath.splitroot("//?/BootPartition/")', ("//?/BootPartition", "/", "")) 184 tester('ntpath.splitroot("//./BootPartition/")', ("//./BootPartition", "/", "")) 185 tester('ntpath.splitroot("//./PhysicalDrive0")', ("//./PhysicalDrive0", "", "")) 186 tester('ntpath.splitroot("//./nul")', ("//./nul", "", "")) 187 188 tester('ntpath.splitroot("\\\\?\\c:")', ("\\\\?\\c:", "", "")) 189 tester('ntpath.splitroot("\\\\.\\c:")', ("\\\\.\\c:", "", "")) 190 tester('ntpath.splitroot("\\\\?\\c:\\")', ("\\\\?\\c:", "\\", "")) 191 tester('ntpath.splitroot("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\", "dir")) 192 tester('ntpath.splitroot("\\\\?\\UNC")', ("\\\\?\\UNC", "", "")) 193 tester('ntpath.splitroot("\\\\?\\UNC\\")', ("\\\\?\\UNC\\", "", "")) 194 tester('ntpath.splitroot("\\\\?\\UNC\\server\\")', ("\\\\?\\UNC\\server\\", "", "")) 195 tester('ntpath.splitroot("\\\\?\\UNC\\server\\share")', 196 ("\\\\?\\UNC\\server\\share", "", "")) 197 tester('ntpath.splitroot("\\\\?\\UNC\\server\\share\\dir")', 198 ("\\\\?\\UNC\\server\\share", "\\", "dir")) 199 tester('ntpath.splitroot("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")', 200 ('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\', 'spam')) 201 tester('ntpath.splitroot("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\", "")) 202 tester('ntpath.splitroot("\\\\.\\BootPartition\\")', ("\\\\.\\BootPartition", "\\", "")) 203 tester('ntpath.splitroot("\\\\.\\PhysicalDrive0")', ("\\\\.\\PhysicalDrive0", "", "")) 204 tester('ntpath.splitroot("\\\\.\\nul")', ("\\\\.\\nul", "", "")) 205 206 # gh-96290: support partial/invalid UNC drives 207 tester('ntpath.splitroot("//")', ("//", "", "")) # empty server & missing share 208 tester('ntpath.splitroot("///")', ("///", "", "")) # empty server & empty share 209 tester('ntpath.splitroot("///y")', ("///y", "", "")) # empty server & non-empty share 210 tester('ntpath.splitroot("//x")', ("//x", "", "")) # non-empty server & missing share 211 tester('ntpath.splitroot("//x/")', ("//x/", "", "")) # non-empty server & empty share 212 213 # gh-101363: match GetFullPathNameW() drive letter parsing behaviour 214 tester('ntpath.splitroot(" :/foo")', (" :", "/", "foo")) 215 tester('ntpath.splitroot("/:/foo")', ("", "/", ":/foo")) 216 217 def test_split(self): 218 tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) 219 tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")', 220 ('\\\\conky\\mountpoint\\foo', 'bar')) 221 222 tester('ntpath.split("c:\\")', ('c:\\', '')) 223 tester('ntpath.split("\\\\conky\\mountpoint\\")', 224 ('\\\\conky\\mountpoint\\', '')) 225 226 tester('ntpath.split("c:/")', ('c:/', '')) 227 tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', '')) 228 229 def test_isabs(self): 230 tester('ntpath.isabs("foo\\bar")', 0) 231 tester('ntpath.isabs("foo/bar")', 0) 232 tester('ntpath.isabs("c:\\")', 1) 233 tester('ntpath.isabs("c:\\foo\\bar")', 1) 234 tester('ntpath.isabs("c:/foo/bar")', 1) 235 tester('ntpath.isabs("\\\\conky\\mountpoint\\")', 1) 236 237 # gh-44626: paths with only a drive or root are not absolute. 238 tester('ntpath.isabs("\\foo\\bar")', 0) 239 tester('ntpath.isabs("/foo/bar")', 0) 240 tester('ntpath.isabs("c:foo\\bar")', 0) 241 tester('ntpath.isabs("c:foo/bar")', 0) 242 243 # gh-96290: normal UNC paths and device paths without trailing backslashes 244 tester('ntpath.isabs("\\\\conky\\mountpoint")', 1) 245 tester('ntpath.isabs("\\\\.\\C:")', 1) 246 247 def test_commonprefix(self): 248 tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])', 249 "/home/swen") 250 tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])', 251 "\\home\\swen\\") 252 tester('ntpath.commonprefix(["/home/swen/spam", "/home/swen/spam"])', 253 "/home/swen/spam") 254 255 def test_join(self): 256 tester('ntpath.join("")', '') 257 tester('ntpath.join("", "", "")', '') 258 tester('ntpath.join("a")', 'a') 259 tester('ntpath.join("/a")', '/a') 260 tester('ntpath.join("\\a")', '\\a') 261 tester('ntpath.join("a:")', 'a:') 262 tester('ntpath.join("a:", "\\b")', 'a:\\b') 263 tester('ntpath.join("a", "\\b")', '\\b') 264 tester('ntpath.join("a", "b", "c")', 'a\\b\\c') 265 tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') 266 tester('ntpath.join("a", "b\\", "c")', 'a\\b\\c') 267 tester('ntpath.join("a", "b", "c\\")', 'a\\b\\c\\') 268 tester('ntpath.join("a", "b", "\\c")', '\\c') 269 tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') 270 tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') 271 272 tester("ntpath.join('', 'a')", 'a') 273 tester("ntpath.join('', '', '', '', 'a')", 'a') 274 tester("ntpath.join('a', '')", 'a\\') 275 tester("ntpath.join('a', '', '', '', '')", 'a\\') 276 tester("ntpath.join('a\\', '')", 'a\\') 277 tester("ntpath.join('a\\', '', '', '', '')", 'a\\') 278 tester("ntpath.join('a/', '')", 'a/') 279 280 tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y') 281 tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y') 282 tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y') 283 tester("ntpath.join('c:', 'x/y')", 'c:x/y') 284 tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y') 285 tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y') 286 tester("ntpath.join('c:/', 'x/y')", 'c:/x/y') 287 tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y') 288 tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y') 289 tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y') 290 tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y') 291 tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y') 292 293 tester("ntpath.join('a/b', '/x/y')", '/x/y') 294 tester("ntpath.join('/a/b', '/x/y')", '/x/y') 295 tester("ntpath.join('c:', '/x/y')", 'c:/x/y') 296 tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y') 297 tester("ntpath.join('c:/', '/x/y')", 'c:/x/y') 298 tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y') 299 tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y') 300 tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y') 301 tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y') 302 303 tester("ntpath.join('c:', 'C:x/y')", 'C:x/y') 304 tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y') 305 tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y') 306 tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y') 307 308 for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b', 309 '//computer/share', '//computer/share/', '//computer/share/a/b'): 310 for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y', 311 '//machine/common', '//machine/common/', '//machine/common/x/y'): 312 tester("ntpath.join(%r, %r)" % (x, y), y) 313 314 tester("ntpath.join('\\\\computer\\share\\', 'a', 'b')", '\\\\computer\\share\\a\\b') 315 tester("ntpath.join('\\\\computer\\share', 'a', 'b')", '\\\\computer\\share\\a\\b') 316 tester("ntpath.join('\\\\computer\\share', 'a\\b')", '\\\\computer\\share\\a\\b') 317 tester("ntpath.join('//computer/share/', 'a', 'b')", '//computer/share/a\\b') 318 tester("ntpath.join('//computer/share', 'a', 'b')", '//computer/share\\a\\b') 319 tester("ntpath.join('//computer/share', 'a/b')", '//computer/share\\a/b') 320 321 tester("ntpath.join('\\\\', 'computer')", '\\\\computer') 322 tester("ntpath.join('\\\\computer\\', 'share')", '\\\\computer\\share') 323 tester("ntpath.join('\\\\computer\\share\\', 'a')", '\\\\computer\\share\\a') 324 tester("ntpath.join('\\\\computer\\share\\a\\', 'b')", '\\\\computer\\share\\a\\b') 325 # Second part is anchored, so that the first part is ignored. 326 tester("ntpath.join('a', 'Z:b', 'c')", 'Z:b\\c') 327 tester("ntpath.join('a', 'Z:\\b', 'c')", 'Z:\\b\\c') 328 tester("ntpath.join('a', '\\\\b\\c', 'd')", '\\\\b\\c\\d') 329 # Second part has a root but not drive. 330 tester("ntpath.join('a', '\\b', 'c')", '\\b\\c') 331 tester("ntpath.join('Z:/a', '/b', 'c')", 'Z:\\b\\c') 332 tester("ntpath.join('//?/Z:/a', '/b', 'c')", '\\\\?\\Z:\\b\\c') 333 tester("ntpath.join('D:a', './c:b')", 'D:a\\.\\c:b') 334 tester("ntpath.join('D:/a', './c:b')", 'D:\\a\\.\\c:b') 335 336 def test_normpath(self): 337 tester("ntpath.normpath('A//////././//.//B')", r'A\B') 338 tester("ntpath.normpath('A/./B')", r'A\B') 339 tester("ntpath.normpath('A/foo/../B')", r'A\B') 340 tester("ntpath.normpath('C:A//B')", r'C:A\B') 341 tester("ntpath.normpath('D:A/./B')", r'D:A\B') 342 tester("ntpath.normpath('e:A/foo/../B')", r'e:A\B') 343 344 tester("ntpath.normpath('C:///A//B')", r'C:\A\B') 345 tester("ntpath.normpath('D:///A/./B')", r'D:\A\B') 346 tester("ntpath.normpath('e:///A/foo/../B')", r'e:\A\B') 347 348 tester("ntpath.normpath('..')", r'..') 349 tester("ntpath.normpath('.')", r'.') 350 tester("ntpath.normpath('c:.')", 'c:') 351 tester("ntpath.normpath('')", r'.') 352 tester("ntpath.normpath('/')", '\\') 353 tester("ntpath.normpath('c:/')", 'c:\\') 354 tester("ntpath.normpath('/../.././..')", '\\') 355 tester("ntpath.normpath('c:/../../..')", 'c:\\') 356 tester("ntpath.normpath('/./a/b')", r'\a\b') 357 tester("ntpath.normpath('c:/./a/b')", r'c:\a\b') 358 tester("ntpath.normpath('../.././..')", r'..\..\..') 359 tester("ntpath.normpath('K:../.././..')", r'K:..\..\..') 360 tester("ntpath.normpath('./a/b')", r'a\b') 361 tester("ntpath.normpath('c:./a/b')", r'c:a\b') 362 tester("ntpath.normpath('C:////a/b')", r'C:\a\b') 363 tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b') 364 365 tester("ntpath.normpath('\\\\.\\NUL')", r'\\.\NUL') 366 tester("ntpath.normpath('\\\\?\\D:/XY\\Z')", r'\\?\D:/XY\Z') 367 tester("ntpath.normpath('handbook/../../Tests/image.png')", r'..\Tests\image.png') 368 tester("ntpath.normpath('handbook/../../../Tests/image.png')", r'..\..\Tests\image.png') 369 tester("ntpath.normpath('handbook///../a/.././../b/c')", r'..\b\c') 370 tester("ntpath.normpath('handbook/a/../..///../../b/c')", r'..\..\b\c') 371 372 tester("ntpath.normpath('//server/share/..')" , '\\\\server\\share\\') 373 tester("ntpath.normpath('//server/share/../')" , '\\\\server\\share\\') 374 tester("ntpath.normpath('//server/share/../..')", '\\\\server\\share\\') 375 tester("ntpath.normpath('//server/share/../../')", '\\\\server\\share\\') 376 377 # gh-96290: don't normalize partial/invalid UNC drives as rooted paths. 378 tester("ntpath.normpath('\\\\foo\\\\')", '\\\\foo\\\\') 379 tester("ntpath.normpath('\\\\foo\\')", '\\\\foo\\') 380 tester("ntpath.normpath('\\\\foo')", '\\\\foo') 381 tester("ntpath.normpath('\\\\')", '\\\\') 382 tester("ntpath.normpath('//?/UNC/server/share/..')", '\\\\?\\UNC\\server\\share\\') 383 384 def test_realpath_curdir(self): 385 expected = ntpath.normpath(os.getcwd()) 386 tester("ntpath.realpath('.')", expected) 387 tester("ntpath.realpath('./.')", expected) 388 tester("ntpath.realpath('/'.join(['.'] * 100))", expected) 389 tester("ntpath.realpath('.\\.')", expected) 390 tester("ntpath.realpath('\\'.join(['.'] * 100))", expected) 391 392 def test_realpath_pardir(self): 393 expected = ntpath.normpath(os.getcwd()) 394 tester("ntpath.realpath('..')", ntpath.dirname(expected)) 395 tester("ntpath.realpath('../..')", 396 ntpath.dirname(ntpath.dirname(expected))) 397 tester("ntpath.realpath('/'.join(['..'] * 50))", 398 ntpath.splitdrive(expected)[0] + '\\') 399 tester("ntpath.realpath('..\\..')", 400 ntpath.dirname(ntpath.dirname(expected))) 401 tester("ntpath.realpath('\\'.join(['..'] * 50))", 402 ntpath.splitdrive(expected)[0] + '\\') 403 404 @os_helper.skip_unless_symlink 405 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 406 def test_realpath_basic(self): 407 ABSTFN = ntpath.abspath(os_helper.TESTFN) 408 open(ABSTFN, "wb").close() 409 self.addCleanup(os_helper.unlink, ABSTFN) 410 self.addCleanup(os_helper.unlink, ABSTFN + "1") 411 412 os.symlink(ABSTFN, ABSTFN + "1") 413 self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN) 414 self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1")), 415 os.fsencode(ABSTFN)) 416 417 # gh-88013: call ntpath.realpath with binary drive name may raise a 418 # TypeError. The drive should not exist to reproduce the bug. 419 drives = {f"{c}:\\" for c in string.ascii_uppercase} - set(os.listdrives()) 420 d = drives.pop().encode() 421 self.assertEqual(ntpath.realpath(d), d) 422 423 # gh-106242: Embedded nulls and non-strict fallback to abspath 424 self.assertEqual(ABSTFN + "\0spam", 425 ntpath.realpath(os_helper.TESTFN + "\0spam", strict=False)) 426 427 @os_helper.skip_unless_symlink 428 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 429 def test_realpath_strict(self): 430 # Bug #43757: raise FileNotFoundError in strict mode if we encounter 431 # a path that does not exist. 432 ABSTFN = ntpath.abspath(os_helper.TESTFN) 433 os.symlink(ABSTFN + "1", ABSTFN) 434 self.addCleanup(os_helper.unlink, ABSTFN) 435 self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN, strict=True) 436 self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN + "2", strict=True) 437 # gh-106242: Embedded nulls should raise OSError (not ValueError) 438 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "\0spam", strict=True) 439 440 @os_helper.skip_unless_symlink 441 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 442 def test_realpath_relative(self): 443 ABSTFN = ntpath.abspath(os_helper.TESTFN) 444 open(ABSTFN, "wb").close() 445 self.addCleanup(os_helper.unlink, ABSTFN) 446 self.addCleanup(os_helper.unlink, ABSTFN + "1") 447 448 os.symlink(ABSTFN, ntpath.relpath(ABSTFN + "1")) 449 self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN) 450 451 @os_helper.skip_unless_symlink 452 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 453 def test_realpath_broken_symlinks(self): 454 ABSTFN = ntpath.abspath(os_helper.TESTFN) 455 os.mkdir(ABSTFN) 456 self.addCleanup(os_helper.rmtree, ABSTFN) 457 458 with os_helper.change_cwd(ABSTFN): 459 os.mkdir("subdir") 460 os.chdir("subdir") 461 os.symlink(".", "recursive") 462 os.symlink("..", "parent") 463 os.chdir("..") 464 os.symlink(".", "self") 465 os.symlink("missing", "broken") 466 os.symlink(r"broken\bar", "broken1") 467 os.symlink(r"self\self\broken", "broken2") 468 os.symlink(r"subdir\parent\subdir\parent\broken", "broken3") 469 os.symlink(ABSTFN + r"\broken", "broken4") 470 os.symlink(r"recursive\..\broken", "broken5") 471 472 self.assertPathEqual(ntpath.realpath("broken"), 473 ABSTFN + r"\missing") 474 self.assertPathEqual(ntpath.realpath(r"broken\foo"), 475 ABSTFN + r"\missing\foo") 476 # bpo-38453: We no longer recursively resolve segments of relative 477 # symlinks that the OS cannot resolve. 478 self.assertPathEqual(ntpath.realpath(r"broken1"), 479 ABSTFN + r"\broken\bar") 480 self.assertPathEqual(ntpath.realpath(r"broken1\baz"), 481 ABSTFN + r"\broken\bar\baz") 482 self.assertPathEqual(ntpath.realpath("broken2"), 483 ABSTFN + r"\self\self\missing") 484 self.assertPathEqual(ntpath.realpath("broken3"), 485 ABSTFN + r"\subdir\parent\subdir\parent\missing") 486 self.assertPathEqual(ntpath.realpath("broken4"), 487 ABSTFN + r"\missing") 488 self.assertPathEqual(ntpath.realpath("broken5"), 489 ABSTFN + r"\missing") 490 491 self.assertPathEqual(ntpath.realpath(b"broken"), 492 os.fsencode(ABSTFN + r"\missing")) 493 self.assertPathEqual(ntpath.realpath(rb"broken\foo"), 494 os.fsencode(ABSTFN + r"\missing\foo")) 495 self.assertPathEqual(ntpath.realpath(rb"broken1"), 496 os.fsencode(ABSTFN + r"\broken\bar")) 497 self.assertPathEqual(ntpath.realpath(rb"broken1\baz"), 498 os.fsencode(ABSTFN + r"\broken\bar\baz")) 499 self.assertPathEqual(ntpath.realpath(b"broken2"), 500 os.fsencode(ABSTFN + r"\self\self\missing")) 501 self.assertPathEqual(ntpath.realpath(rb"broken3"), 502 os.fsencode(ABSTFN + r"\subdir\parent\subdir\parent\missing")) 503 self.assertPathEqual(ntpath.realpath(b"broken4"), 504 os.fsencode(ABSTFN + r"\missing")) 505 self.assertPathEqual(ntpath.realpath(b"broken5"), 506 os.fsencode(ABSTFN + r"\missing")) 507 508 @os_helper.skip_unless_symlink 509 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 510 def test_realpath_symlink_loops(self): 511 # Symlink loops in non-strict mode are non-deterministic as to which 512 # path is returned, but it will always be the fully resolved path of 513 # one member of the cycle 514 ABSTFN = ntpath.abspath(os_helper.TESTFN) 515 self.addCleanup(os_helper.unlink, ABSTFN) 516 self.addCleanup(os_helper.unlink, ABSTFN + "1") 517 self.addCleanup(os_helper.unlink, ABSTFN + "2") 518 self.addCleanup(os_helper.unlink, ABSTFN + "y") 519 self.addCleanup(os_helper.unlink, ABSTFN + "c") 520 self.addCleanup(os_helper.unlink, ABSTFN + "a") 521 522 os.symlink(ABSTFN, ABSTFN) 523 self.assertPathEqual(ntpath.realpath(ABSTFN), ABSTFN) 524 525 os.symlink(ABSTFN + "1", ABSTFN + "2") 526 os.symlink(ABSTFN + "2", ABSTFN + "1") 527 expected = (ABSTFN + "1", ABSTFN + "2") 528 self.assertPathIn(ntpath.realpath(ABSTFN + "1"), expected) 529 self.assertPathIn(ntpath.realpath(ABSTFN + "2"), expected) 530 531 self.assertPathIn(ntpath.realpath(ABSTFN + "1\\x"), 532 (ntpath.join(r, "x") for r in expected)) 533 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\.."), 534 ntpath.dirname(ABSTFN)) 535 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x"), 536 ntpath.dirname(ABSTFN) + "\\x") 537 os.symlink(ABSTFN + "x", ABSTFN + "y") 538 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\" 539 + ntpath.basename(ABSTFN) + "y"), 540 ABSTFN + "x") 541 self.assertPathIn(ntpath.realpath(ABSTFN + "1\\..\\" 542 + ntpath.basename(ABSTFN) + "1"), 543 expected) 544 545 os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") 546 self.assertPathEqual(ntpath.realpath(ABSTFN + "a"), ABSTFN + "a") 547 548 os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN)) 549 + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c") 550 self.assertPathEqual(ntpath.realpath(ABSTFN + "c"), ABSTFN + "c") 551 552 # Test using relative path as well. 553 self.assertPathEqual(ntpath.realpath(ntpath.basename(ABSTFN)), ABSTFN) 554 555 @os_helper.skip_unless_symlink 556 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 557 def test_realpath_symlink_loops_strict(self): 558 # Symlink loops raise OSError in strict mode 559 ABSTFN = ntpath.abspath(os_helper.TESTFN) 560 self.addCleanup(os_helper.unlink, ABSTFN) 561 self.addCleanup(os_helper.unlink, ABSTFN + "1") 562 self.addCleanup(os_helper.unlink, ABSTFN + "2") 563 self.addCleanup(os_helper.unlink, ABSTFN + "y") 564 self.addCleanup(os_helper.unlink, ABSTFN + "c") 565 self.addCleanup(os_helper.unlink, ABSTFN + "a") 566 567 os.symlink(ABSTFN, ABSTFN) 568 self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=True) 569 570 os.symlink(ABSTFN + "1", ABSTFN + "2") 571 os.symlink(ABSTFN + "2", ABSTFN + "1") 572 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=True) 573 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=True) 574 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=True) 575 # Windows eliminates '..' components before resolving links, so the 576 # following call is not expected to raise. 577 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=True), 578 ntpath.dirname(ABSTFN)) 579 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\x", strict=True) 580 os.symlink(ABSTFN + "x", ABSTFN + "y") 581 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\" 582 + ntpath.basename(ABSTFN) + "y", 583 strict=True) 584 self.assertRaises(OSError, ntpath.realpath, 585 ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1", 586 strict=True) 587 588 os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") 589 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=True) 590 591 os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN)) 592 + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c") 593 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=True) 594 595 # Test using relative path as well. 596 self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN), 597 strict=True) 598 599 @os_helper.skip_unless_symlink 600 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 601 def test_realpath_symlink_prefix(self): 602 ABSTFN = ntpath.abspath(os_helper.TESTFN) 603 self.addCleanup(os_helper.unlink, ABSTFN + "3") 604 self.addCleanup(os_helper.unlink, "\\\\?\\" + ABSTFN + "3.") 605 self.addCleanup(os_helper.unlink, ABSTFN + "3link") 606 self.addCleanup(os_helper.unlink, ABSTFN + "3.link") 607 608 with open(ABSTFN + "3", "wb") as f: 609 f.write(b'0') 610 os.symlink(ABSTFN + "3", ABSTFN + "3link") 611 612 with open("\\\\?\\" + ABSTFN + "3.", "wb") as f: 613 f.write(b'1') 614 os.symlink("\\\\?\\" + ABSTFN + "3.", ABSTFN + "3.link") 615 616 self.assertPathEqual(ntpath.realpath(ABSTFN + "3link"), 617 ABSTFN + "3") 618 self.assertPathEqual(ntpath.realpath(ABSTFN + "3.link"), 619 "\\\\?\\" + ABSTFN + "3.") 620 621 # Resolved paths should be usable to open target files 622 with open(ntpath.realpath(ABSTFN + "3link"), "rb") as f: 623 self.assertEqual(f.read(), b'0') 624 with open(ntpath.realpath(ABSTFN + "3.link"), "rb") as f: 625 self.assertEqual(f.read(), b'1') 626 627 # When the prefix is included, it is not stripped 628 self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3link"), 629 "\\\\?\\" + ABSTFN + "3") 630 self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3.link"), 631 "\\\\?\\" + ABSTFN + "3.") 632 633 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 634 def test_realpath_nul(self): 635 tester("ntpath.realpath('NUL')", r'\\.\NUL') 636 637 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 638 @unittest.skipUnless(HAVE_GETSHORTPATHNAME, 'need _getshortpathname') 639 def test_realpath_cwd(self): 640 ABSTFN = ntpath.abspath(os_helper.TESTFN) 641 642 os_helper.unlink(ABSTFN) 643 os_helper.rmtree(ABSTFN) 644 os.mkdir(ABSTFN) 645 self.addCleanup(os_helper.rmtree, ABSTFN) 646 647 test_dir_long = ntpath.join(ABSTFN, "MyVeryLongDirectoryName") 648 os.mkdir(test_dir_long) 649 650 test_dir_short = _getshortpathname(test_dir_long) 651 test_file_long = ntpath.join(test_dir_long, "file.txt") 652 test_file_short = ntpath.join(test_dir_short, "file.txt") 653 654 with open(test_file_long, "wb") as f: 655 f.write(b"content") 656 657 self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short)) 658 659 with os_helper.change_cwd(test_dir_long): 660 self.assertPathEqual(test_file_long, ntpath.realpath("file.txt")) 661 with os_helper.change_cwd(test_dir_long.lower()): 662 self.assertPathEqual(test_file_long, ntpath.realpath("file.txt")) 663 with os_helper.change_cwd(test_dir_short): 664 self.assertPathEqual(test_file_long, ntpath.realpath("file.txt")) 665 666 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 667 def test_realpath_permission(self): 668 # Test whether python can resolve the real filename of a 669 # shortened file name even if it does not have permission to access it. 670 ABSTFN = ntpath.realpath(os_helper.TESTFN) 671 672 os_helper.unlink(ABSTFN) 673 os_helper.rmtree(ABSTFN) 674 os.mkdir(ABSTFN) 675 self.addCleanup(os_helper.rmtree, ABSTFN) 676 677 test_file = ntpath.join(ABSTFN, "LongFileName123.txt") 678 test_file_short = ntpath.join(ABSTFN, "LONGFI~1.TXT") 679 680 with open(test_file, "wb") as f: 681 f.write(b"content") 682 # Automatic generation of short names may be disabled on 683 # NTFS volumes for the sake of performance. 684 # They're not supported at all on ReFS and exFAT. 685 subprocess.run( 686 # Try to set the short name manually. 687 ['fsutil.exe', 'file', 'setShortName', test_file, 'LONGFI~1.TXT'], 688 creationflags=subprocess.DETACHED_PROCESS 689 ) 690 691 try: 692 self.assertPathEqual(test_file, ntpath.realpath(test_file_short)) 693 except AssertionError: 694 raise unittest.SkipTest('the filesystem seems to lack support for short filenames') 695 696 # Deny the right to [S]YNCHRONIZE on the file to 697 # force nt._getfinalpathname to fail with ERROR_ACCESS_DENIED. 698 p = subprocess.run( 699 ['icacls.exe', test_file, '/deny', '*S-1-5-32-545:(S)'], 700 creationflags=subprocess.DETACHED_PROCESS 701 ) 702 703 if p.returncode: 704 raise unittest.SkipTest('failed to deny access to the test file') 705 706 self.assertPathEqual(test_file, ntpath.realpath(test_file_short)) 707 708 def test_expandvars(self): 709 with os_helper.EnvironmentVarGuard() as env: 710 env.clear() 711 env["foo"] = "bar" 712 env["{foo"] = "baz1" 713 env["{foo}"] = "baz2" 714 tester('ntpath.expandvars("foo")', "foo") 715 tester('ntpath.expandvars("$foo bar")', "bar bar") 716 tester('ntpath.expandvars("${foo}bar")', "barbar") 717 tester('ntpath.expandvars("$[foo]bar")', "$[foo]bar") 718 tester('ntpath.expandvars("$bar bar")', "$bar bar") 719 tester('ntpath.expandvars("$?bar")', "$?bar") 720 tester('ntpath.expandvars("$foo}bar")', "bar}bar") 721 tester('ntpath.expandvars("${foo")', "${foo") 722 tester('ntpath.expandvars("${{foo}}")', "baz1}") 723 tester('ntpath.expandvars("$foo$foo")', "barbar") 724 tester('ntpath.expandvars("$bar$bar")', "$bar$bar") 725 tester('ntpath.expandvars("%foo% bar")', "bar bar") 726 tester('ntpath.expandvars("%foo%bar")', "barbar") 727 tester('ntpath.expandvars("%foo%%foo%")', "barbar") 728 tester('ntpath.expandvars("%%foo%%foo%foo%")', "%foo%foobar") 729 tester('ntpath.expandvars("%?bar%")', "%?bar%") 730 tester('ntpath.expandvars("%foo%%bar")', "bar%bar") 731 tester('ntpath.expandvars("\'%foo%\'%bar")', "\'%foo%\'%bar") 732 tester('ntpath.expandvars("bar\'%foo%")', "bar\'%foo%") 733 734 @unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII') 735 def test_expandvars_nonascii(self): 736 def check(value, expected): 737 tester('ntpath.expandvars(%r)' % value, expected) 738 with os_helper.EnvironmentVarGuard() as env: 739 env.clear() 740 nonascii = os_helper.FS_NONASCII 741 env['spam'] = nonascii 742 env[nonascii] = 'ham' + nonascii 743 check('$spam bar', '%s bar' % nonascii) 744 check('$%s bar' % nonascii, '$%s bar' % nonascii) 745 check('${spam}bar', '%sbar' % nonascii) 746 check('${%s}bar' % nonascii, 'ham%sbar' % nonascii) 747 check('$spam}bar', '%s}bar' % nonascii) 748 check('$%s}bar' % nonascii, '$%s}bar' % nonascii) 749 check('%spam% bar', '%s bar' % nonascii) 750 check('%{}% bar'.format(nonascii), 'ham%s bar' % nonascii) 751 check('%spam%bar', '%sbar' % nonascii) 752 check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii) 753 754 def test_expanduser(self): 755 tester('ntpath.expanduser("test")', 'test') 756 757 with os_helper.EnvironmentVarGuard() as env: 758 env.clear() 759 tester('ntpath.expanduser("~test")', '~test') 760 761 env['HOMEDRIVE'] = 'C:\\' 762 env['HOMEPATH'] = 'Users\\eric' 763 env['USERNAME'] = 'eric' 764 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 765 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 766 767 del env['HOMEDRIVE'] 768 tester('ntpath.expanduser("~test")', 'Users\\test') 769 tester('ntpath.expanduser("~")', 'Users\\eric') 770 771 env.clear() 772 env['USERPROFILE'] = 'C:\\Users\\eric' 773 env['USERNAME'] = 'eric' 774 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 775 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 776 tester('ntpath.expanduser("~test\\foo\\bar")', 777 'C:\\Users\\test\\foo\\bar') 778 tester('ntpath.expanduser("~test/foo/bar")', 779 'C:\\Users\\test/foo/bar') 780 tester('ntpath.expanduser("~\\foo\\bar")', 781 'C:\\Users\\eric\\foo\\bar') 782 tester('ntpath.expanduser("~/foo/bar")', 783 'C:\\Users\\eric/foo/bar') 784 785 # bpo-36264: ignore `HOME` when set on windows 786 env.clear() 787 env['HOME'] = 'F:\\' 788 env['USERPROFILE'] = 'C:\\Users\\eric' 789 env['USERNAME'] = 'eric' 790 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 791 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 792 793 # bpo-39899: don't guess another user's home directory if 794 # `%USERNAME% != basename(%USERPROFILE%)` 795 env.clear() 796 env['USERPROFILE'] = 'C:\\Users\\eric' 797 env['USERNAME'] = 'idle' 798 tester('ntpath.expanduser("~test")', '~test') 799 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 800 801 802 803 @unittest.skipUnless(nt, "abspath requires 'nt' module") 804 def test_abspath(self): 805 tester('ntpath.abspath("C:\\")', "C:\\") 806 tester('ntpath.abspath("\\\\?\\C:////spam////eggs. . .")', "\\\\?\\C:\\spam\\eggs") 807 tester('ntpath.abspath("\\\\.\\C:////spam////eggs. . .")', "\\\\.\\C:\\spam\\eggs") 808 tester('ntpath.abspath("//spam//eggs. . .")', "\\\\spam\\eggs") 809 tester('ntpath.abspath("\\\\spam\\\\eggs. . .")', "\\\\spam\\eggs") 810 tester('ntpath.abspath("C:/spam. . .")', "C:\\spam") 811 tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam") 812 tester('ntpath.abspath("C:/nul")', "\\\\.\\nul") 813 tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul") 814 self.assertTrue(ntpath.isabs(ntpath.abspath("C:spam"))) 815 self.assertEqual(ntpath.abspath("C:\x00"), ntpath.join(ntpath.abspath("C:"), "\x00")) 816 self.assertEqual(ntpath.abspath("\x00:spam"), "\x00:\\spam") 817 tester('ntpath.abspath("//..")', "\\\\") 818 tester('ntpath.abspath("//../")', "\\\\..\\") 819 tester('ntpath.abspath("//../..")', "\\\\..\\") 820 tester('ntpath.abspath("//../../")', "\\\\..\\..\\") 821 tester('ntpath.abspath("//../../../")', "\\\\..\\..\\") 822 tester('ntpath.abspath("//../../../..")', "\\\\..\\..\\") 823 tester('ntpath.abspath("//../../../../")', "\\\\..\\..\\") 824 tester('ntpath.abspath("//server")', "\\\\server") 825 tester('ntpath.abspath("//server/")', "\\\\server\\") 826 tester('ntpath.abspath("//server/..")', "\\\\server\\") 827 tester('ntpath.abspath("//server/../")', "\\\\server\\..\\") 828 tester('ntpath.abspath("//server/../..")', "\\\\server\\..\\") 829 tester('ntpath.abspath("//server/../../")', "\\\\server\\..\\") 830 tester('ntpath.abspath("//server/../../..")', "\\\\server\\..\\") 831 tester('ntpath.abspath("//server/../../../")', "\\\\server\\..\\") 832 tester('ntpath.abspath("//server/share")', "\\\\server\\share") 833 tester('ntpath.abspath("//server/share/")', "\\\\server\\share\\") 834 tester('ntpath.abspath("//server/share/..")', "\\\\server\\share\\") 835 tester('ntpath.abspath("//server/share/../")', "\\\\server\\share\\") 836 tester('ntpath.abspath("//server/share/../..")', "\\\\server\\share\\") 837 tester('ntpath.abspath("//server/share/../../")', "\\\\server\\share\\") 838 tester('ntpath.abspath("C:\\nul. . .")', "\\\\.\\nul") 839 tester('ntpath.abspath("//... . .")', "\\\\") 840 tester('ntpath.abspath("//.. . . .")', "\\\\") 841 tester('ntpath.abspath("//../... . .")', "\\\\..\\") 842 tester('ntpath.abspath("//../.. . . .")', "\\\\..\\") 843 with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir: # bpo-31047 844 tester('ntpath.abspath("")', cwd_dir) 845 tester('ntpath.abspath(" ")', cwd_dir + "\\ ") 846 tester('ntpath.abspath("?")', cwd_dir + "\\?") 847 drive, _ = ntpath.splitdrive(cwd_dir) 848 tester('ntpath.abspath("/abc/")', drive + "\\abc") 849 850 def test_relpath(self): 851 tester('ntpath.relpath("a")', 'a') 852 tester('ntpath.relpath(ntpath.abspath("a"))', 'a') 853 tester('ntpath.relpath("a/b")', 'a\\b') 854 tester('ntpath.relpath("../a/b")', '..\\a\\b') 855 with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir: 856 currentdir = ntpath.basename(cwd_dir) 857 tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a') 858 tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b') 859 tester('ntpath.relpath("a", "b/c")', '..\\..\\a') 860 tester('ntpath.relpath("c:/foo/bar/bat", "c:/x/y")', '..\\..\\foo\\bar\\bat') 861 tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a') 862 tester('ntpath.relpath("a", "a")', '.') 863 tester('ntpath.relpath("/foo/bar/bat", "/x/y/z")', '..\\..\\..\\foo\\bar\\bat') 864 tester('ntpath.relpath("/foo/bar/bat", "/foo/bar")', 'bat') 865 tester('ntpath.relpath("/foo/bar/bat", "/")', 'foo\\bar\\bat') 866 tester('ntpath.relpath("/", "/foo/bar/bat")', '..\\..\\..') 867 tester('ntpath.relpath("/foo/bar/bat", "/x")', '..\\foo\\bar\\bat') 868 tester('ntpath.relpath("/x", "/foo/bar/bat")', '..\\..\\..\\x') 869 tester('ntpath.relpath("/", "/")', '.') 870 tester('ntpath.relpath("/a", "/a")', '.') 871 tester('ntpath.relpath("/a/b", "/a/b")', '.') 872 tester('ntpath.relpath("c:/foo", "C:/FOO")', '.') 873 874 def test_commonpath(self): 875 def check(paths, expected): 876 tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'), 877 expected) 878 def check_error(paths, expected): 879 self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths) 880 self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths[::-1]) 881 self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, 882 [os.fsencode(p) for p in paths]) 883 self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, 884 [os.fsencode(p) for p in paths[::-1]]) 885 886 self.assertRaises(TypeError, ntpath.commonpath, None) 887 self.assertRaises(ValueError, ntpath.commonpath, []) 888 self.assertRaises(ValueError, ntpath.commonpath, iter([])) 889 890 # gh-117381: Logical error messages 891 check_error(['C:\\Foo', 'C:Foo'], "Can't mix absolute and relative paths") 892 check_error(['C:\\Foo', '\\Foo'], "Paths don't have the same drive") 893 check_error(['C:\\Foo', 'Foo'], "Paths don't have the same drive") 894 check_error(['C:Foo', '\\Foo'], "Paths don't have the same drive") 895 check_error(['C:Foo', 'Foo'], "Paths don't have the same drive") 896 check_error(['\\Foo', 'Foo'], "Can't mix rooted and not-rooted paths") 897 898 check(['C:\\Foo'], 'C:\\Foo') 899 check(['C:\\Foo', 'C:\\Foo'], 'C:\\Foo') 900 check(['C:\\Foo\\', 'C:\\Foo'], 'C:\\Foo') 901 check(['C:\\Foo\\', 'C:\\Foo\\'], 'C:\\Foo') 902 check(['C:\\\\Foo', 'C:\\Foo\\\\'], 'C:\\Foo') 903 check(['C:\\.\\Foo', 'C:\\Foo\\.'], 'C:\\Foo') 904 check(['C:\\', 'C:\\baz'], 'C:\\') 905 check(['C:\\Bar', 'C:\\baz'], 'C:\\') 906 check(['C:\\Foo', 'C:\\Foo\\Baz'], 'C:\\Foo') 907 check(['C:\\Foo\\Bar', 'C:\\Foo\\Baz'], 'C:\\Foo') 908 check(['C:\\Bar', 'C:\\Baz'], 'C:\\') 909 check(['C:\\Bar\\', 'C:\\Baz'], 'C:\\') 910 911 check(['C:\\Foo\\Bar', 'C:/Foo/Baz'], 'C:\\Foo') 912 check(['C:\\Foo\\Bar', 'c:/foo/baz'], 'C:\\Foo') 913 check(['c:/foo/bar', 'C:\\Foo\\Baz'], 'c:\\foo') 914 915 # gh-117381: Logical error messages 916 check_error(['C:\\Foo', 'D:\\Foo'], "Paths don't have the same drive") 917 check_error(['C:\\Foo', 'D:Foo'], "Paths don't have the same drive") 918 check_error(['C:Foo', 'D:Foo'], "Paths don't have the same drive") 919 920 check(['spam'], 'spam') 921 check(['spam', 'spam'], 'spam') 922 check(['spam', 'alot'], '') 923 check(['and\\jam', 'and\\spam'], 'and') 924 check(['and\\\\jam', 'and\\spam\\\\'], 'and') 925 check(['and\\.\\jam', '.\\and\\spam'], 'and') 926 check(['and\\jam', 'and\\spam', 'alot'], '') 927 check(['and\\jam', 'and\\spam', 'and'], 'and') 928 check(['C:and\\jam', 'C:and\\spam'], 'C:and') 929 930 check([''], '') 931 check(['', 'spam\\alot'], '') 932 933 # gh-117381: Logical error messages 934 check_error(['', '\\spam\\alot'], "Can't mix rooted and not-rooted paths") 935 936 self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'C:\\Foo\\Baz']) 937 self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'Foo\\Baz']) 938 self.assertRaises(TypeError, ntpath.commonpath, [b'Foo', 'C:\\Foo\\Baz']) 939 self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'C:\\Foo\\Baz']) 940 self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz']) 941 self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz']) 942 943 @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.") 944 def test_sameopenfile(self): 945 with TemporaryFile() as tf1, TemporaryFile() as tf2: 946 # Make sure the same file is really the same 947 self.assertTrue(ntpath.sameopenfile(tf1.fileno(), tf1.fileno())) 948 # Make sure different files are really different 949 self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno())) 950 # Make sure invalid values don't cause issues on win32 951 if sys.platform == "win32": 952 with self.assertRaises(OSError): 953 # Invalid file descriptors shouldn't display assert 954 # dialogs (#4804) 955 ntpath.sameopenfile(-1, -1) 956 957 def test_ismount(self): 958 self.assertTrue(ntpath.ismount("c:\\")) 959 self.assertTrue(ntpath.ismount("C:\\")) 960 self.assertTrue(ntpath.ismount("c:/")) 961 self.assertTrue(ntpath.ismount("C:/")) 962 self.assertTrue(ntpath.ismount("\\\\.\\c:\\")) 963 self.assertTrue(ntpath.ismount("\\\\.\\C:\\")) 964 965 self.assertTrue(ntpath.ismount(b"c:\\")) 966 self.assertTrue(ntpath.ismount(b"C:\\")) 967 self.assertTrue(ntpath.ismount(b"c:/")) 968 self.assertTrue(ntpath.ismount(b"C:/")) 969 self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) 970 self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) 971 972 with os_helper.temp_dir() as d: 973 self.assertFalse(ntpath.ismount(d)) 974 975 if sys.platform == "win32": 976 # 977 # Make sure the current folder isn't the root folder 978 # (or any other volume root). The drive-relative 979 # locations below cannot then refer to mount points 980 # 981 test_cwd = os.getenv("SystemRoot") 982 drive, path = ntpath.splitdrive(test_cwd) 983 with os_helper.change_cwd(test_cwd): 984 self.assertFalse(ntpath.ismount(drive.lower())) 985 self.assertFalse(ntpath.ismount(drive.upper())) 986 987 self.assertTrue(ntpath.ismount("\\\\localhost\\c$")) 988 self.assertTrue(ntpath.ismount("\\\\localhost\\c$\\")) 989 990 self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$")) 991 self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$\\")) 992 993 def test_isreserved(self): 994 self.assertFalse(ntpath.isreserved('')) 995 self.assertFalse(ntpath.isreserved('.')) 996 self.assertFalse(ntpath.isreserved('..')) 997 self.assertFalse(ntpath.isreserved('/')) 998 self.assertFalse(ntpath.isreserved('/foo/bar')) 999 # A name that ends with a space or dot is reserved. 1000 self.assertTrue(ntpath.isreserved('foo.')) 1001 self.assertTrue(ntpath.isreserved('foo ')) 1002 # ASCII control characters are reserved. 1003 self.assertTrue(ntpath.isreserved('\foo')) 1004 # Wildcard characters, colon, and pipe are reserved. 1005 self.assertTrue(ntpath.isreserved('foo*bar')) 1006 self.assertTrue(ntpath.isreserved('foo?bar')) 1007 self.assertTrue(ntpath.isreserved('foo"bar')) 1008 self.assertTrue(ntpath.isreserved('foo<bar')) 1009 self.assertTrue(ntpath.isreserved('foo>bar')) 1010 self.assertTrue(ntpath.isreserved('foo:bar')) 1011 self.assertTrue(ntpath.isreserved('foo|bar')) 1012 # Case-insensitive DOS-device names are reserved. 1013 self.assertTrue(ntpath.isreserved('nul')) 1014 self.assertTrue(ntpath.isreserved('aux')) 1015 self.assertTrue(ntpath.isreserved('prn')) 1016 self.assertTrue(ntpath.isreserved('con')) 1017 self.assertTrue(ntpath.isreserved('conin$')) 1018 self.assertTrue(ntpath.isreserved('conout$')) 1019 # COM/LPT + 1-9 or + superscript 1-3 are reserved. 1020 self.assertTrue(ntpath.isreserved('COM1')) 1021 self.assertTrue(ntpath.isreserved('LPT9')) 1022 self.assertTrue(ntpath.isreserved('com\xb9')) 1023 self.assertTrue(ntpath.isreserved('com\xb2')) 1024 self.assertTrue(ntpath.isreserved('lpt\xb3')) 1025 # DOS-device name matching ignores characters after a dot or 1026 # a colon and also ignores trailing spaces. 1027 self.assertTrue(ntpath.isreserved('NUL.txt')) 1028 self.assertTrue(ntpath.isreserved('PRN ')) 1029 self.assertTrue(ntpath.isreserved('AUX .txt')) 1030 self.assertTrue(ntpath.isreserved('COM1:bar')) 1031 self.assertTrue(ntpath.isreserved('LPT9 :bar')) 1032 # DOS-device names are only matched at the beginning 1033 # of a path component. 1034 self.assertFalse(ntpath.isreserved('bar.com9')) 1035 self.assertFalse(ntpath.isreserved('bar.lpt9')) 1036 # The entire path is checked, except for the drive. 1037 self.assertTrue(ntpath.isreserved('c:/bar/baz/NUL')) 1038 self.assertTrue(ntpath.isreserved('c:/NUL/bar/baz')) 1039 self.assertFalse(ntpath.isreserved('//./NUL')) 1040 # Bytes are supported. 1041 self.assertFalse(ntpath.isreserved(b'')) 1042 self.assertFalse(ntpath.isreserved(b'.')) 1043 self.assertFalse(ntpath.isreserved(b'..')) 1044 self.assertFalse(ntpath.isreserved(b'/')) 1045 self.assertFalse(ntpath.isreserved(b'/foo/bar')) 1046 self.assertTrue(ntpath.isreserved(b'foo.')) 1047 self.assertTrue(ntpath.isreserved(b'nul')) 1048 1049 def assertEqualCI(self, s1, s2): 1050 """Assert that two strings are equal ignoring case differences.""" 1051 self.assertEqual(s1.lower(), s2.lower()) 1052 1053 @unittest.skipUnless(nt, "OS helpers require 'nt' module") 1054 def test_nt_helpers(self): 1055 # Trivial validation that the helpers do not break, and support both 1056 # unicode and bytes (UTF-8) paths 1057 1058 executable = nt._getfinalpathname(sys.executable) 1059 1060 for path in executable, os.fsencode(executable): 1061 volume_path = nt._getvolumepathname(path) 1062 path_drive = ntpath.splitdrive(path)[0] 1063 volume_path_drive = ntpath.splitdrive(volume_path)[0] 1064 self.assertEqualCI(path_drive, volume_path_drive) 1065 1066 cap, free = nt._getdiskusage(sys.exec_prefix) 1067 self.assertGreater(cap, 0) 1068 self.assertGreater(free, 0) 1069 b_cap, b_free = nt._getdiskusage(sys.exec_prefix.encode()) 1070 # Free space may change, so only test the capacity is equal 1071 self.assertEqual(b_cap, cap) 1072 self.assertGreater(b_free, 0) 1073 1074 for path in [sys.prefix, sys.executable]: 1075 final_path = nt._getfinalpathname(path) 1076 self.assertIsInstance(final_path, str) 1077 self.assertGreater(len(final_path), 0) 1078 1079 b_final_path = nt._getfinalpathname(path.encode()) 1080 self.assertIsInstance(b_final_path, bytes) 1081 self.assertGreater(len(b_final_path), 0) 1082 1083 @unittest.skipIf(sys.platform != 'win32', "Can only test junctions with creation on win32.") 1084 def test_isjunction(self): 1085 with os_helper.temp_dir() as d: 1086 with os_helper.change_cwd(d): 1087 os.mkdir('tmpdir') 1088 1089 import _winapi 1090 try: 1091 _winapi.CreateJunction('tmpdir', 'testjunc') 1092 except OSError: 1093 raise unittest.SkipTest('creating the test junction failed') 1094 1095 self.assertTrue(ntpath.isjunction('testjunc')) 1096 self.assertFalse(ntpath.isjunction('tmpdir')) 1097 self.assertPathEqual(ntpath.realpath('testjunc'), ntpath.realpath('tmpdir')) 1098 1099 @unittest.skipIf(sys.platform != 'win32', "drive letters are a windows concept") 1100 def test_isfile_driveletter(self): 1101 drive = os.environ.get('SystemDrive') 1102 if drive is None or len(drive) != 2 or drive[1] != ':': 1103 raise unittest.SkipTest('SystemDrive is not defined or malformed') 1104 self.assertFalse(os.path.isfile('\\\\.\\' + drive)) 1105 1106 @unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()") 1107 def test_isfile_anonymous_pipe(self): 1108 pr, pw = os.pipe() 1109 try: 1110 self.assertFalse(ntpath.isfile(pr)) 1111 finally: 1112 os.close(pr) 1113 os.close(pw) 1114 1115 @unittest.skipIf(sys.platform != 'win32', "windows only") 1116 def test_isfile_named_pipe(self): 1117 import _winapi 1118 named_pipe = f'//./PIPE/python_isfile_test_{os.getpid()}' 1119 h = _winapi.CreateNamedPipe(named_pipe, 1120 _winapi.PIPE_ACCESS_INBOUND, 1121 0, 1, 0, 0, 0, 0) 1122 try: 1123 self.assertFalse(ntpath.isfile(named_pipe)) 1124 finally: 1125 _winapi.CloseHandle(h) 1126 1127 @unittest.skipIf(sys.platform != 'win32', "windows only") 1128 def test_con_device(self): 1129 self.assertFalse(os.path.isfile(r"\\.\CON")) 1130 self.assertFalse(os.path.isdir(r"\\.\CON")) 1131 self.assertFalse(os.path.islink(r"\\.\CON")) 1132 self.assertTrue(os.path.exists(r"\\.\CON")) 1133 1134 @unittest.skipIf(sys.platform != 'win32', "Fast paths are only for win32") 1135 @cpython_only 1136 def test_fast_paths_in_use(self): 1137 # There are fast paths of these functions implemented in posixmodule.c. 1138 # Confirm that they are being used, and not the Python fallbacks in 1139 # genericpath.py. 1140 self.assertTrue(os.path.splitroot is nt._path_splitroot_ex) 1141 self.assertFalse(inspect.isfunction(os.path.splitroot)) 1142 self.assertTrue(os.path.normpath is nt._path_normpath) 1143 self.assertFalse(inspect.isfunction(os.path.normpath)) 1144 self.assertTrue(os.path.isdir is nt._path_isdir) 1145 self.assertFalse(inspect.isfunction(os.path.isdir)) 1146 self.assertTrue(os.path.isfile is nt._path_isfile) 1147 self.assertFalse(inspect.isfunction(os.path.isfile)) 1148 self.assertTrue(os.path.islink is nt._path_islink) 1149 self.assertFalse(inspect.isfunction(os.path.islink)) 1150 self.assertTrue(os.path.isjunction is nt._path_isjunction) 1151 self.assertFalse(inspect.isfunction(os.path.isjunction)) 1152 self.assertTrue(os.path.exists is nt._path_exists) 1153 self.assertFalse(inspect.isfunction(os.path.exists)) 1154 self.assertTrue(os.path.lexists is nt._path_lexists) 1155 self.assertFalse(inspect.isfunction(os.path.lexists)) 1156 1157 @unittest.skipIf(os.name != 'nt', "Dev Drives only exist on Win32") 1158 def test_isdevdrive(self): 1159 # Result may be True or False, but shouldn't raise 1160 self.assertIn(ntpath.isdevdrive(os_helper.TESTFN), (True, False)) 1161 # ntpath.isdevdrive can handle relative paths 1162 self.assertIn(ntpath.isdevdrive("."), (True, False)) 1163 self.assertIn(ntpath.isdevdrive(b"."), (True, False)) 1164 # Volume syntax is supported 1165 self.assertIn(ntpath.isdevdrive(os.listvolumes()[0]), (True, False)) 1166 # Invalid volume returns False from os.path method 1167 self.assertFalse(ntpath.isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\")) 1168 # Invalid volume raises from underlying helper 1169 with self.assertRaises(OSError): 1170 nt._path_isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\") 1171 1172 @unittest.skipIf(os.name == 'nt', "isdevdrive fallback only used off Win32") 1173 def test_isdevdrive_fallback(self): 1174 # Fallback always returns False 1175 self.assertFalse(ntpath.isdevdrive(os_helper.TESTFN)) 1176 1177 1178class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase): 1179 pathmodule = ntpath 1180 attributes = ['relpath'] 1181 1182 1183class PathLikeTests(NtpathTestCase): 1184 1185 path = ntpath 1186 1187 def setUp(self): 1188 self.file_name = os_helper.TESTFN 1189 self.file_path = FakePath(os_helper.TESTFN) 1190 self.addCleanup(os_helper.unlink, self.file_name) 1191 with open(self.file_name, 'xb', 0) as file: 1192 file.write(b"test_ntpath.PathLikeTests") 1193 1194 def _check_function(self, func): 1195 self.assertPathEqual(func(self.file_path), func(self.file_name)) 1196 1197 def test_path_normcase(self): 1198 self._check_function(self.path.normcase) 1199 if sys.platform == 'win32': 1200 self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ') 1201 self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def') 1202 1203 def test_path_isabs(self): 1204 self._check_function(self.path.isabs) 1205 1206 def test_path_join(self): 1207 self.assertEqual(self.path.join('a', FakePath('b'), 'c'), 1208 self.path.join('a', 'b', 'c')) 1209 1210 def test_path_split(self): 1211 self._check_function(self.path.split) 1212 1213 def test_path_splitext(self): 1214 self._check_function(self.path.splitext) 1215 1216 def test_path_splitdrive(self): 1217 self._check_function(self.path.splitdrive) 1218 1219 def test_path_splitroot(self): 1220 self._check_function(self.path.splitroot) 1221 1222 def test_path_basename(self): 1223 self._check_function(self.path.basename) 1224 1225 def test_path_dirname(self): 1226 self._check_function(self.path.dirname) 1227 1228 def test_path_islink(self): 1229 self._check_function(self.path.islink) 1230 1231 def test_path_lexists(self): 1232 self._check_function(self.path.lexists) 1233 1234 def test_path_ismount(self): 1235 self._check_function(self.path.ismount) 1236 1237 def test_path_expanduser(self): 1238 self._check_function(self.path.expanduser) 1239 1240 def test_path_expandvars(self): 1241 self._check_function(self.path.expandvars) 1242 1243 def test_path_normpath(self): 1244 self._check_function(self.path.normpath) 1245 1246 def test_path_abspath(self): 1247 self._check_function(self.path.abspath) 1248 1249 def test_path_realpath(self): 1250 self._check_function(self.path.realpath) 1251 1252 def test_path_relpath(self): 1253 self._check_function(self.path.relpath) 1254 1255 def test_path_commonpath(self): 1256 common_path = self.path.commonpath([self.file_path, self.file_name]) 1257 self.assertPathEqual(common_path, self.file_name) 1258 1259 def test_path_isdir(self): 1260 self._check_function(self.path.isdir) 1261 1262 1263if __name__ == "__main__": 1264 unittest.main() 1265