1import ntpath 2import os 3import string 4import subprocess 5import sys 6import unittest 7import warnings 8from ntpath import ALLOW_MISSING 9from test.support import 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 80def _parameterize(*parameters): 81 """Simplistic decorator to parametrize a test 82 83 Runs the decorated test multiple times in subTest, with a value from 84 'parameters' passed as an extra positional argument. 85 Calls doCleanups() after each run. 86 87 Not for general use. Intended to avoid indenting for easier backports. 88 89 See https://discuss.python.org/t/91827 for discussing generalizations. 90 """ 91 def _parametrize_decorator(func): 92 def _parameterized(self, *args, **kwargs): 93 for parameter in parameters: 94 with self.subTest(parameter): 95 func(self, *args, parameter, **kwargs) 96 self.doCleanups() 97 return _parameterized 98 return _parametrize_decorator 99 100 101class NtpathTestCase(unittest.TestCase): 102 def assertPathEqual(self, path1, path2): 103 if path1 == path2 or _norm(path1) == _norm(path2): 104 return 105 self.assertEqual(path1, path2) 106 107 def assertPathIn(self, path, pathset): 108 self.assertIn(_norm(path), _norm(pathset)) 109 110 111class TestNtpath(NtpathTestCase): 112 def test_splitext(self): 113 tester('ntpath.splitext("foo.ext")', ('foo', '.ext')) 114 tester('ntpath.splitext("/foo/foo.ext")', ('/foo/foo', '.ext')) 115 tester('ntpath.splitext(".ext")', ('.ext', '')) 116 tester('ntpath.splitext("\\foo.ext\\foo")', ('\\foo.ext\\foo', '')) 117 tester('ntpath.splitext("foo.ext\\")', ('foo.ext\\', '')) 118 tester('ntpath.splitext("")', ('', '')) 119 tester('ntpath.splitext("foo.bar.ext")', ('foo.bar', '.ext')) 120 tester('ntpath.splitext("xx/foo.bar.ext")', ('xx/foo.bar', '.ext')) 121 tester('ntpath.splitext("xx\\foo.bar.ext")', ('xx\\foo.bar', '.ext')) 122 tester('ntpath.splitext("c:a/b\\c.d")', ('c:a/b\\c', '.d')) 123 124 def test_splitdrive(self): 125 tester('ntpath.splitdrive("c:\\foo\\bar")', 126 ('c:', '\\foo\\bar')) 127 tester('ntpath.splitdrive("c:/foo/bar")', 128 ('c:', '/foo/bar')) 129 tester('ntpath.splitdrive("\\\\conky\\mountpoint\\foo\\bar")', 130 ('\\\\conky\\mountpoint', '\\foo\\bar')) 131 tester('ntpath.splitdrive("//conky/mountpoint/foo/bar")', 132 ('//conky/mountpoint', '/foo/bar')) 133 tester('ntpath.splitdrive("\\\\\\conky\\mountpoint\\foo\\bar")', 134 ('\\\\\\conky', '\\mountpoint\\foo\\bar')) 135 tester('ntpath.splitdrive("///conky/mountpoint/foo/bar")', 136 ('///conky', '/mountpoint/foo/bar')) 137 tester('ntpath.splitdrive("\\\\conky\\\\mountpoint\\foo\\bar")', 138 ('\\\\conky\\', '\\mountpoint\\foo\\bar')) 139 tester('ntpath.splitdrive("//conky//mountpoint/foo/bar")', 140 ('//conky/', '/mountpoint/foo/bar')) 141 # Issue #19911: UNC part containing U+0130 142 self.assertEqual(ntpath.splitdrive('//conky/MOUNTPOİNT/foo/bar'), 143 ('//conky/MOUNTPOİNT', '/foo/bar')) 144 145 # gh-81790: support device namespace, including UNC drives. 146 tester('ntpath.splitdrive("//?/c:")', ("//?/c:", "")) 147 tester('ntpath.splitdrive("//?/c:/")', ("//?/c:", "/")) 148 tester('ntpath.splitdrive("//?/c:/dir")', ("//?/c:", "/dir")) 149 tester('ntpath.splitdrive("//?/UNC")', ("//?/UNC", "")) 150 tester('ntpath.splitdrive("//?/UNC/")', ("//?/UNC/", "")) 151 tester('ntpath.splitdrive("//?/UNC/server/")', ("//?/UNC/server/", "")) 152 tester('ntpath.splitdrive("//?/UNC/server/share")', ("//?/UNC/server/share", "")) 153 tester('ntpath.splitdrive("//?/UNC/server/share/dir")', ("//?/UNC/server/share", "/dir")) 154 tester('ntpath.splitdrive("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")', 155 ('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/spam')) 156 tester('ntpath.splitdrive("//?/BootPartition/")', ("//?/BootPartition", "/")) 157 158 tester('ntpath.splitdrive("\\\\?\\c:")', ("\\\\?\\c:", "")) 159 tester('ntpath.splitdrive("\\\\?\\c:\\")', ("\\\\?\\c:", "\\")) 160 tester('ntpath.splitdrive("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\dir")) 161 tester('ntpath.splitdrive("\\\\?\\UNC")', ("\\\\?\\UNC", "")) 162 tester('ntpath.splitdrive("\\\\?\\UNC\\")', ("\\\\?\\UNC\\", "")) 163 tester('ntpath.splitdrive("\\\\?\\UNC\\server\\")', ("\\\\?\\UNC\\server\\", "")) 164 tester('ntpath.splitdrive("\\\\?\\UNC\\server\\share")', ("\\\\?\\UNC\\server\\share", "")) 165 tester('ntpath.splitdrive("\\\\?\\UNC\\server\\share\\dir")', 166 ("\\\\?\\UNC\\server\\share", "\\dir")) 167 tester('ntpath.splitdrive("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")', 168 ('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\spam')) 169 tester('ntpath.splitdrive("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\")) 170 171 # gh-96290: support partial/invalid UNC drives 172 tester('ntpath.splitdrive("//")', ("//", "")) # empty server & missing share 173 tester('ntpath.splitdrive("///")', ("///", "")) # empty server & empty share 174 tester('ntpath.splitdrive("///y")', ("///y", "")) # empty server & non-empty share 175 tester('ntpath.splitdrive("//x")', ("//x", "")) # non-empty server & missing share 176 tester('ntpath.splitdrive("//x/")', ("//x/", "")) # non-empty server & empty share 177 178 def test_split(self): 179 tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) 180 tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")', 181 ('\\\\conky\\mountpoint\\foo', 'bar')) 182 183 tester('ntpath.split("c:\\")', ('c:\\', '')) 184 tester('ntpath.split("\\\\conky\\mountpoint\\")', 185 ('\\\\conky\\mountpoint\\', '')) 186 187 tester('ntpath.split("c:/")', ('c:/', '')) 188 tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', '')) 189 190 def test_isabs(self): 191 tester('ntpath.isabs("c:\\")', 1) 192 tester('ntpath.isabs("\\\\conky\\mountpoint\\")', 1) 193 tester('ntpath.isabs("\\foo")', 1) 194 tester('ntpath.isabs("\\foo\\bar")', 1) 195 196 # gh-96290: normal UNC paths and device paths without trailing backslashes 197 tester('ntpath.isabs("\\\\conky\\mountpoint")', 1) 198 tester('ntpath.isabs("\\\\.\\C:")', 1) 199 200 def test_commonprefix(self): 201 tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])', 202 "/home/swen") 203 tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])', 204 "\\home\\swen\\") 205 tester('ntpath.commonprefix(["/home/swen/spam", "/home/swen/spam"])', 206 "/home/swen/spam") 207 208 def test_join(self): 209 tester('ntpath.join("")', '') 210 tester('ntpath.join("", "", "")', '') 211 tester('ntpath.join("a")', 'a') 212 tester('ntpath.join("/a")', '/a') 213 tester('ntpath.join("\\a")', '\\a') 214 tester('ntpath.join("a:")', 'a:') 215 tester('ntpath.join("a:", "\\b")', 'a:\\b') 216 tester('ntpath.join("a", "\\b")', '\\b') 217 tester('ntpath.join("a", "b", "c")', 'a\\b\\c') 218 tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') 219 tester('ntpath.join("a", "b\\", "c")', 'a\\b\\c') 220 tester('ntpath.join("a", "b", "\\c")', '\\c') 221 tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') 222 tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') 223 224 tester("ntpath.join('', 'a')", 'a') 225 tester("ntpath.join('', '', '', '', 'a')", 'a') 226 tester("ntpath.join('a', '')", 'a\\') 227 tester("ntpath.join('a', '', '', '', '')", 'a\\') 228 tester("ntpath.join('a\\', '')", 'a\\') 229 tester("ntpath.join('a\\', '', '', '', '')", 'a\\') 230 tester("ntpath.join('a/', '')", 'a/') 231 232 tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y') 233 tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y') 234 tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y') 235 tester("ntpath.join('c:', 'x/y')", 'c:x/y') 236 tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y') 237 tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y') 238 tester("ntpath.join('c:/', 'x/y')", 'c:/x/y') 239 tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y') 240 tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y') 241 tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y') 242 tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y') 243 tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y') 244 245 tester("ntpath.join('a/b', '/x/y')", '/x/y') 246 tester("ntpath.join('/a/b', '/x/y')", '/x/y') 247 tester("ntpath.join('c:', '/x/y')", 'c:/x/y') 248 tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y') 249 tester("ntpath.join('c:/', '/x/y')", 'c:/x/y') 250 tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y') 251 tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y') 252 tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y') 253 tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y') 254 255 tester("ntpath.join('c:', 'C:x/y')", 'C:x/y') 256 tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y') 257 tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y') 258 tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y') 259 260 for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b', 261 '//computer/share', '//computer/share/', '//computer/share/a/b'): 262 for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y', 263 '//machine/common', '//machine/common/', '//machine/common/x/y'): 264 tester("ntpath.join(%r, %r)" % (x, y), y) 265 266 tester("ntpath.join('\\\\computer\\share\\', 'a', 'b')", '\\\\computer\\share\\a\\b') 267 tester("ntpath.join('\\\\computer\\share', 'a', 'b')", '\\\\computer\\share\\a\\b') 268 tester("ntpath.join('\\\\computer\\share', 'a\\b')", '\\\\computer\\share\\a\\b') 269 tester("ntpath.join('//computer/share/', 'a', 'b')", '//computer/share/a\\b') 270 tester("ntpath.join('//computer/share', 'a', 'b')", '//computer/share\\a\\b') 271 tester("ntpath.join('//computer/share', 'a/b')", '//computer/share\\a/b') 272 273 def test_normpath(self): 274 tester("ntpath.normpath('A//////././//.//B')", r'A\B') 275 tester("ntpath.normpath('A/./B')", r'A\B') 276 tester("ntpath.normpath('A/foo/../B')", r'A\B') 277 tester("ntpath.normpath('C:A//B')", r'C:A\B') 278 tester("ntpath.normpath('D:A/./B')", r'D:A\B') 279 tester("ntpath.normpath('e:A/foo/../B')", r'e:A\B') 280 281 tester("ntpath.normpath('C:///A//B')", r'C:\A\B') 282 tester("ntpath.normpath('D:///A/./B')", r'D:\A\B') 283 tester("ntpath.normpath('e:///A/foo/../B')", r'e:\A\B') 284 285 tester("ntpath.normpath('..')", r'..') 286 tester("ntpath.normpath('.')", r'.') 287 tester("ntpath.normpath('')", r'.') 288 tester("ntpath.normpath('/')", '\\') 289 tester("ntpath.normpath('c:/')", 'c:\\') 290 tester("ntpath.normpath('/../.././..')", '\\') 291 tester("ntpath.normpath('c:/../../..')", 'c:\\') 292 tester("ntpath.normpath('../.././..')", r'..\..\..') 293 tester("ntpath.normpath('K:../.././..')", r'K:..\..\..') 294 tester("ntpath.normpath('C:////a/b')", r'C:\a\b') 295 tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b') 296 297 tester("ntpath.normpath('\\\\.\\NUL')", r'\\.\NUL') 298 tester("ntpath.normpath('\\\\?\\D:/XY\\Z')", r'\\?\D:/XY\Z') 299 tester("ntpath.normpath('handbook/../../Tests/image.png')", r'..\Tests\image.png') 300 tester("ntpath.normpath('handbook/../../../Tests/image.png')", r'..\..\Tests\image.png') 301 tester("ntpath.normpath('handbook///../a/.././../b/c')", r'..\b\c') 302 tester("ntpath.normpath('handbook/a/../..///../../b/c')", r'..\..\b\c') 303 304 tester("ntpath.normpath('//server/share/..')" , '\\\\server\\share\\') 305 tester("ntpath.normpath('//server/share/../')" , '\\\\server\\share\\') 306 tester("ntpath.normpath('//server/share/../..')", '\\\\server\\share\\') 307 tester("ntpath.normpath('//server/share/../../')", '\\\\server\\share\\') 308 309 # gh-96290: don't normalize partial/invalid UNC drives as rooted paths. 310 tester("ntpath.normpath('\\\\foo\\\\')", '\\\\foo\\\\') 311 tester("ntpath.normpath('\\\\foo\\')", '\\\\foo\\') 312 tester("ntpath.normpath('\\\\foo')", '\\\\foo') 313 tester("ntpath.normpath('\\\\')", '\\\\') 314 315 def test_realpath_curdir(self): 316 expected = ntpath.normpath(os.getcwd()) 317 tester("ntpath.realpath('.')", expected) 318 tester("ntpath.realpath('./.')", expected) 319 tester("ntpath.realpath('/'.join(['.'] * 100))", expected) 320 tester("ntpath.realpath('.\\.')", expected) 321 tester("ntpath.realpath('\\'.join(['.'] * 100))", expected) 322 323 def test_realpath_curdir_strict(self): 324 expected = ntpath.normpath(os.getcwd()) 325 tester("ntpath.realpath('.', strict=True)", expected) 326 tester("ntpath.realpath('./.', strict=True)", expected) 327 tester("ntpath.realpath('/'.join(['.'] * 100), strict=True)", expected) 328 tester("ntpath.realpath('.\\.', strict=True)", expected) 329 tester("ntpath.realpath('\\'.join(['.'] * 100), strict=True)", expected) 330 331 def test_realpath_curdir_missing_ok(self): 332 expected = ntpath.normpath(os.getcwd()) 333 tester("ntpath.realpath('.', strict=ALLOW_MISSING)", 334 expected) 335 tester("ntpath.realpath('./.', strict=ALLOW_MISSING)", 336 expected) 337 tester("ntpath.realpath('/'.join(['.'] * 100), strict=ALLOW_MISSING)", 338 expected) 339 tester("ntpath.realpath('.\\.', strict=ALLOW_MISSING)", 340 expected) 341 tester("ntpath.realpath('\\'.join(['.'] * 100), strict=ALLOW_MISSING)", 342 expected) 343 344 def test_realpath_pardir(self): 345 expected = ntpath.normpath(os.getcwd()) 346 tester("ntpath.realpath('..')", ntpath.dirname(expected)) 347 tester("ntpath.realpath('../..')", 348 ntpath.dirname(ntpath.dirname(expected))) 349 tester("ntpath.realpath('/'.join(['..'] * 50))", 350 ntpath.splitdrive(expected)[0] + '\\') 351 tester("ntpath.realpath('..\\..')", 352 ntpath.dirname(ntpath.dirname(expected))) 353 tester("ntpath.realpath('\\'.join(['..'] * 50))", 354 ntpath.splitdrive(expected)[0] + '\\') 355 356 def test_realpath_pardir_strict(self): 357 expected = ntpath.normpath(os.getcwd()) 358 tester("ntpath.realpath('..', strict=True)", ntpath.dirname(expected)) 359 tester("ntpath.realpath('../..', strict=True)", 360 ntpath.dirname(ntpath.dirname(expected))) 361 tester("ntpath.realpath('/'.join(['..'] * 50), strict=True)", 362 ntpath.splitdrive(expected)[0] + '\\') 363 tester("ntpath.realpath('..\\..', strict=True)", 364 ntpath.dirname(ntpath.dirname(expected))) 365 tester("ntpath.realpath('\\'.join(['..'] * 50), strict=True)", 366 ntpath.splitdrive(expected)[0] + '\\') 367 368 def test_realpath_pardir_missing_ok(self): 369 expected = ntpath.normpath(os.getcwd()) 370 tester("ntpath.realpath('..', strict=ALLOW_MISSING)", 371 ntpath.dirname(expected)) 372 tester("ntpath.realpath('../..', strict=ALLOW_MISSING)", 373 ntpath.dirname(ntpath.dirname(expected))) 374 tester("ntpath.realpath('/'.join(['..'] * 50), strict=ALLOW_MISSING)", 375 ntpath.splitdrive(expected)[0] + '\\') 376 tester("ntpath.realpath('..\\..', strict=ALLOW_MISSING)", 377 ntpath.dirname(ntpath.dirname(expected))) 378 tester("ntpath.realpath('\\'.join(['..'] * 50), strict=ALLOW_MISSING)", 379 ntpath.splitdrive(expected)[0] + '\\') 380 381 @os_helper.skip_unless_symlink 382 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 383 @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) 384 def test_realpath_basic(self, kwargs): 385 ABSTFN = ntpath.abspath(os_helper.TESTFN) 386 open(ABSTFN, "wb").close() 387 self.addCleanup(os_helper.unlink, ABSTFN) 388 self.addCleanup(os_helper.unlink, ABSTFN + "1") 389 390 os.symlink(ABSTFN, ABSTFN + "1") 391 self.assertPathEqual(ntpath.realpath(ABSTFN + "1", **kwargs), ABSTFN) 392 self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1"), **kwargs), 393 os.fsencode(ABSTFN)) 394 395 # gh-88013: call ntpath.realpath with binary drive name may raise a 396 # TypeError. The drive should not exist to reproduce the bug. 397 for c in string.ascii_uppercase: 398 d = f"{c}:\\" 399 if not ntpath.exists(d): 400 break 401 else: 402 raise OSError("No free drive letters available") 403 self.assertEqual(ntpath.realpath(d), d) 404 405 # gh-106242: Embedded nulls and non-strict fallback to abspath 406 if kwargs: 407 with self.assertRaises(OSError): 408 ntpath.realpath(os_helper.TESTFN + "\0spam", 409 **kwargs) 410 else: 411 self.assertEqual(ABSTFN + "\0spam", 412 ntpath.realpath(os_helper.TESTFN + "\0spam", **kwargs)) 413 414 @os_helper.skip_unless_symlink 415 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 416 def test_realpath_strict(self): 417 # Bug #43757: raise FileNotFoundError in strict mode if we encounter 418 # a path that does not exist. 419 ABSTFN = ntpath.abspath(os_helper.TESTFN) 420 os.symlink(ABSTFN + "1", ABSTFN) 421 self.addCleanup(os_helper.unlink, ABSTFN) 422 self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN, strict=True) 423 self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN + "2", strict=True) 424 425 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 426 def test_realpath_invalid_paths(self): 427 realpath = ntpath.realpath 428 ABSTFN = ntpath.abspath(os_helper.TESTFN) 429 ABSTFNb = os.fsencode(ABSTFN) 430 path = ABSTFN + '\x00' 431 # gh-106242: Embedded nulls and non-strict fallback to abspath 432 self.assertEqual(realpath(path, strict=False), path) 433 # gh-106242: Embedded nulls should raise OSError (not ValueError) 434 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 435 self.assertRaises(OSError, ntpath.realpath, path, strict=ALLOW_MISSING) 436 path = ABSTFNb + b'\x00' 437 self.assertEqual(realpath(path, strict=False), path) 438 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 439 self.assertRaises(OSError, ntpath.realpath, path, strict=ALLOW_MISSING) 440 path = ABSTFN + '\\nonexistent\\x\x00' 441 self.assertEqual(realpath(path, strict=False), path) 442 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 443 self.assertRaises(OSError, ntpath.realpath, path, strict=ALLOW_MISSING) 444 path = ABSTFNb + b'\\nonexistent\\x\x00' 445 self.assertEqual(realpath(path, strict=False), path) 446 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 447 self.assertRaises(OSError, ntpath.realpath, path, strict=ALLOW_MISSING) 448 path = ABSTFN + '\x00\\..' 449 self.assertEqual(realpath(path, strict=False), os.getcwd()) 450 self.assertEqual(realpath(path, strict=True), os.getcwd()) 451 self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwd()) 452 path = ABSTFNb + b'\x00\\..' 453 self.assertEqual(realpath(path, strict=False), os.getcwdb()) 454 self.assertEqual(realpath(path, strict=True), os.getcwdb()) 455 self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwdb()) 456 path = ABSTFN + '\\nonexistent\\x\x00\\..' 457 self.assertEqual(realpath(path, strict=False), ABSTFN + '\\nonexistent') 458 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 459 self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFN + '\\nonexistent') 460 path = ABSTFNb + b'\\nonexistent\\x\x00\\..' 461 self.assertEqual(realpath(path, strict=False), ABSTFNb + b'\\nonexistent') 462 self.assertRaises(OSError, ntpath.realpath, path, strict=True) 463 self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFNb + b'\\nonexistent') 464 465 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 466 @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) 467 def test_realpath_invalid_unicode_paths(self, kwargs): 468 realpath = ntpath.realpath 469 ABSTFN = ntpath.abspath(os_helper.TESTFN) 470 ABSTFNb = os.fsencode(ABSTFN) 471 path = ABSTFNb + b'\xff' 472 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 473 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 474 path = ABSTFNb + b'\\nonexistent\\\xff' 475 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 476 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 477 path = ABSTFNb + b'\xff\\..' 478 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 479 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 480 path = ABSTFNb + b'\\nonexistent\\\xff\\..' 481 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 482 self.assertRaises(UnicodeDecodeError, ntpath.realpath, path, **kwargs) 483 484 @os_helper.skip_unless_symlink 485 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 486 @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) 487 def test_realpath_relative(self, kwargs): 488 ABSTFN = ntpath.abspath(os_helper.TESTFN) 489 open(ABSTFN, "wb").close() 490 self.addCleanup(os_helper.unlink, ABSTFN) 491 self.addCleanup(os_helper.unlink, ABSTFN + "1") 492 493 os.symlink(ABSTFN, ntpath.relpath(ABSTFN + "1")) 494 self.assertPathEqual(ntpath.realpath(ABSTFN + "1", **kwargs), ABSTFN) 495 496 @os_helper.skip_unless_symlink 497 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 498 def test_realpath_broken_symlinks(self): 499 ABSTFN = ntpath.abspath(os_helper.TESTFN) 500 os.mkdir(ABSTFN) 501 self.addCleanup(os_helper.rmtree, ABSTFN) 502 503 with os_helper.change_cwd(ABSTFN): 504 os.mkdir("subdir") 505 os.chdir("subdir") 506 os.symlink(".", "recursive") 507 os.symlink("..", "parent") 508 os.chdir("..") 509 os.symlink(".", "self") 510 os.symlink("missing", "broken") 511 os.symlink(r"broken\bar", "broken1") 512 os.symlink(r"self\self\broken", "broken2") 513 os.symlink(r"subdir\parent\subdir\parent\broken", "broken3") 514 os.symlink(ABSTFN + r"\broken", "broken4") 515 os.symlink(r"recursive\..\broken", "broken5") 516 517 self.assertPathEqual(ntpath.realpath("broken"), 518 ABSTFN + r"\missing") 519 self.assertPathEqual(ntpath.realpath(r"broken\foo"), 520 ABSTFN + r"\missing\foo") 521 # bpo-38453: We no longer recursively resolve segments of relative 522 # symlinks that the OS cannot resolve. 523 self.assertPathEqual(ntpath.realpath(r"broken1"), 524 ABSTFN + r"\broken\bar") 525 self.assertPathEqual(ntpath.realpath(r"broken1\baz"), 526 ABSTFN + r"\broken\bar\baz") 527 self.assertPathEqual(ntpath.realpath("broken2"), 528 ABSTFN + r"\self\self\missing") 529 self.assertPathEqual(ntpath.realpath("broken3"), 530 ABSTFN + r"\subdir\parent\subdir\parent\missing") 531 self.assertPathEqual(ntpath.realpath("broken4"), 532 ABSTFN + r"\missing") 533 self.assertPathEqual(ntpath.realpath("broken5"), 534 ABSTFN + r"\missing") 535 536 self.assertPathEqual(ntpath.realpath(b"broken"), 537 os.fsencode(ABSTFN + r"\missing")) 538 self.assertPathEqual(ntpath.realpath(rb"broken\foo"), 539 os.fsencode(ABSTFN + r"\missing\foo")) 540 self.assertPathEqual(ntpath.realpath(rb"broken1"), 541 os.fsencode(ABSTFN + r"\broken\bar")) 542 self.assertPathEqual(ntpath.realpath(rb"broken1\baz"), 543 os.fsencode(ABSTFN + r"\broken\bar\baz")) 544 self.assertPathEqual(ntpath.realpath(b"broken2"), 545 os.fsencode(ABSTFN + r"\self\self\missing")) 546 self.assertPathEqual(ntpath.realpath(rb"broken3"), 547 os.fsencode(ABSTFN + r"\subdir\parent\subdir\parent\missing")) 548 self.assertPathEqual(ntpath.realpath(b"broken4"), 549 os.fsencode(ABSTFN + r"\missing")) 550 self.assertPathEqual(ntpath.realpath(b"broken5"), 551 os.fsencode(ABSTFN + r"\missing")) 552 553 @os_helper.skip_unless_symlink 554 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 555 def test_realpath_symlink_loops(self): 556 # Symlink loops in non-strict mode are non-deterministic as to which 557 # path is returned, but it will always be the fully resolved path of 558 # one member of the cycle 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.assertPathEqual(ntpath.realpath(ABSTFN), ABSTFN) 569 570 os.symlink(ABSTFN + "1", ABSTFN + "2") 571 os.symlink(ABSTFN + "2", ABSTFN + "1") 572 expected = (ABSTFN + "1", ABSTFN + "2") 573 self.assertPathIn(ntpath.realpath(ABSTFN + "1"), expected) 574 self.assertPathIn(ntpath.realpath(ABSTFN + "2"), expected) 575 576 self.assertPathIn(ntpath.realpath(ABSTFN + "1\\x"), 577 (ntpath.join(r, "x") for r in expected)) 578 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\.."), 579 ntpath.dirname(ABSTFN)) 580 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x"), 581 ntpath.dirname(ABSTFN) + "\\x") 582 os.symlink(ABSTFN + "x", ABSTFN + "y") 583 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\" 584 + ntpath.basename(ABSTFN) + "y"), 585 ABSTFN + "x") 586 self.assertPathIn(ntpath.realpath(ABSTFN + "1\\..\\" 587 + ntpath.basename(ABSTFN) + "1"), 588 expected) 589 590 os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") 591 self.assertPathEqual(ntpath.realpath(ABSTFN + "a"), ABSTFN + "a") 592 593 os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN)) 594 + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c") 595 self.assertPathEqual(ntpath.realpath(ABSTFN + "c"), ABSTFN + "c") 596 597 # Test using relative path as well. 598 self.assertPathEqual(ntpath.realpath(ntpath.basename(ABSTFN)), ABSTFN) 599 600 @os_helper.skip_unless_symlink 601 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 602 def test_realpath_symlink_loops_strict(self): 603 # Symlink loops raise OSError in strict mode 604 ABSTFN = ntpath.abspath(os_helper.TESTFN) 605 self.addCleanup(os_helper.unlink, ABSTFN) 606 self.addCleanup(os_helper.unlink, ABSTFN + "1") 607 self.addCleanup(os_helper.unlink, ABSTFN + "2") 608 self.addCleanup(os_helper.unlink, ABSTFN + "y") 609 self.addCleanup(os_helper.unlink, ABSTFN + "c") 610 self.addCleanup(os_helper.unlink, ABSTFN + "a") 611 612 os.symlink(ABSTFN, ABSTFN) 613 self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=True) 614 615 os.symlink(ABSTFN + "1", ABSTFN + "2") 616 os.symlink(ABSTFN + "2", ABSTFN + "1") 617 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=True) 618 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=True) 619 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=True) 620 # Windows eliminates '..' components before resolving links, so the 621 # following call is not expected to raise. 622 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=True), 623 ntpath.dirname(ABSTFN)) 624 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\x", strict=True) 625 os.symlink(ABSTFN + "x", ABSTFN + "y") 626 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\" 627 + ntpath.basename(ABSTFN) + "y", 628 strict=True) 629 self.assertRaises(OSError, ntpath.realpath, 630 ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1", 631 strict=True) 632 633 os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") 634 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=True) 635 636 os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN)) 637 + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c") 638 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=True) 639 640 # Test using relative path as well. 641 self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN), 642 strict=True) 643 644 @os_helper.skip_unless_symlink 645 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 646 def test_realpath_symlink_loops_raise(self): 647 # Symlink loops raise OSError in ALLOW_MISSING mode 648 ABSTFN = ntpath.abspath(os_helper.TESTFN) 649 self.addCleanup(os_helper.unlink, ABSTFN) 650 self.addCleanup(os_helper.unlink, ABSTFN + "1") 651 self.addCleanup(os_helper.unlink, ABSTFN + "2") 652 self.addCleanup(os_helper.unlink, ABSTFN + "y") 653 self.addCleanup(os_helper.unlink, ABSTFN + "c") 654 self.addCleanup(os_helper.unlink, ABSTFN + "a") 655 self.addCleanup(os_helper.unlink, ABSTFN + "x") 656 657 os.symlink(ABSTFN, ABSTFN) 658 self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=ALLOW_MISSING) 659 660 os.symlink(ABSTFN + "1", ABSTFN + "2") 661 os.symlink(ABSTFN + "2", ABSTFN + "1") 662 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", 663 strict=ALLOW_MISSING) 664 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", 665 strict=ALLOW_MISSING) 666 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", 667 strict=ALLOW_MISSING) 668 669 # Windows eliminates '..' components before resolving links; 670 # realpath is not expected to raise if this removes the loop. 671 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\.."), 672 ntpath.dirname(ABSTFN)) 673 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x"), 674 ntpath.dirname(ABSTFN) + "\\x") 675 676 os.symlink(ABSTFN + "x", ABSTFN + "y") 677 self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\" 678 + ntpath.basename(ABSTFN) + "y"), 679 ABSTFN + "x") 680 self.assertRaises( 681 OSError, ntpath.realpath, 682 ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1", 683 strict=ALLOW_MISSING) 684 685 os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") 686 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", 687 strict=ALLOW_MISSING) 688 689 os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN)) 690 + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c") 691 self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", 692 strict=ALLOW_MISSING) 693 694 # Test using relative path as well. 695 self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN), 696 strict=ALLOW_MISSING) 697 698 @os_helper.skip_unless_symlink 699 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 700 @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) 701 def test_realpath_symlink_prefix(self, kwargs): 702 ABSTFN = ntpath.abspath(os_helper.TESTFN) 703 self.addCleanup(os_helper.unlink, ABSTFN + "3") 704 self.addCleanup(os_helper.unlink, "\\\\?\\" + ABSTFN + "3.") 705 self.addCleanup(os_helper.unlink, ABSTFN + "3link") 706 self.addCleanup(os_helper.unlink, ABSTFN + "3.link") 707 708 with open(ABSTFN + "3", "wb") as f: 709 f.write(b'0') 710 os.symlink(ABSTFN + "3", ABSTFN + "3link") 711 712 with open("\\\\?\\" + ABSTFN + "3.", "wb") as f: 713 f.write(b'1') 714 os.symlink("\\\\?\\" + ABSTFN + "3.", ABSTFN + "3.link") 715 716 self.assertPathEqual(ntpath.realpath(ABSTFN + "3link", **kwargs), 717 ABSTFN + "3") 718 self.assertPathEqual(ntpath.realpath(ABSTFN + "3.link", **kwargs), 719 "\\\\?\\" + ABSTFN + "3.") 720 721 # Resolved paths should be usable to open target files 722 with open(ntpath.realpath(ABSTFN + "3link"), "rb") as f: 723 self.assertEqual(f.read(), b'0') 724 with open(ntpath.realpath(ABSTFN + "3.link"), "rb") as f: 725 self.assertEqual(f.read(), b'1') 726 727 # When the prefix is included, it is not stripped 728 self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3link", **kwargs), 729 "\\\\?\\" + ABSTFN + "3") 730 self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3.link", **kwargs), 731 "\\\\?\\" + ABSTFN + "3.") 732 733 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 734 def test_realpath_nul(self): 735 tester("ntpath.realpath('NUL')", r'\\.\NUL') 736 tester("ntpath.realpath('NUL', strict=False)", r'\\.\NUL') 737 tester("ntpath.realpath('NUL', strict=True)", r'\\.\NUL') 738 tester("ntpath.realpath('NUL', strict=ALLOW_MISSING)", r'\\.\NUL') 739 740 @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') 741 @unittest.skipUnless(HAVE_GETSHORTPATHNAME, 'need _getshortpathname') 742 def test_realpath_cwd(self): 743 ABSTFN = ntpath.abspath(os_helper.TESTFN) 744 745 os_helper.unlink(ABSTFN) 746 os_helper.rmtree(ABSTFN) 747 os.mkdir(ABSTFN) 748 self.addCleanup(os_helper.rmtree, ABSTFN) 749 750 test_dir_long = ntpath.join(ABSTFN, "MyVeryLongDirectoryName") 751 os.mkdir(test_dir_long) 752 753 test_dir_short = _getshortpathname(test_dir_long) 754 test_file_long = ntpath.join(test_dir_long, "file.txt") 755 test_file_short = ntpath.join(test_dir_short, "file.txt") 756 757 with open(test_file_long, "wb") as f: 758 f.write(b"content") 759 760 self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short)) 761 762 for kwargs in {}, {'strict': True}, {'strict': ALLOW_MISSING}: 763 with self.subTest(**kwargs): 764 with os_helper.change_cwd(test_dir_long): 765 self.assertPathEqual( 766 test_file_long, 767 ntpath.realpath("file.txt", **kwargs)) 768 with os_helper.change_cwd(test_dir_long.lower()): 769 self.assertPathEqual( 770 test_file_long, 771 ntpath.realpath("file.txt", **kwargs)) 772 with os_helper.change_cwd(test_dir_short): 773 self.assertPathEqual( 774 test_file_long, 775 ntpath.realpath("file.txt", **kwargs)) 776 777 def test_expandvars(self): 778 with os_helper.EnvironmentVarGuard() as env: 779 env.clear() 780 env["foo"] = "bar" 781 env["{foo"] = "baz1" 782 env["{foo}"] = "baz2" 783 tester('ntpath.expandvars("foo")', "foo") 784 tester('ntpath.expandvars("$foo bar")', "bar bar") 785 tester('ntpath.expandvars("${foo}bar")', "barbar") 786 tester('ntpath.expandvars("$[foo]bar")', "$[foo]bar") 787 tester('ntpath.expandvars("$bar bar")', "$bar bar") 788 tester('ntpath.expandvars("$?bar")', "$?bar") 789 tester('ntpath.expandvars("$foo}bar")', "bar}bar") 790 tester('ntpath.expandvars("${foo")', "${foo") 791 tester('ntpath.expandvars("${{foo}}")', "baz1}") 792 tester('ntpath.expandvars("$foo$foo")', "barbar") 793 tester('ntpath.expandvars("$bar$bar")', "$bar$bar") 794 tester('ntpath.expandvars("%foo% bar")', "bar bar") 795 tester('ntpath.expandvars("%foo%bar")', "barbar") 796 tester('ntpath.expandvars("%foo%%foo%")', "barbar") 797 tester('ntpath.expandvars("%%foo%%foo%foo%")', "%foo%foobar") 798 tester('ntpath.expandvars("%?bar%")', "%?bar%") 799 tester('ntpath.expandvars("%foo%%bar")', "bar%bar") 800 tester('ntpath.expandvars("\'%foo%\'%bar")', "\'%foo%\'%bar") 801 tester('ntpath.expandvars("bar\'%foo%")', "bar\'%foo%") 802 803 @unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII') 804 def test_expandvars_nonascii(self): 805 def check(value, expected): 806 tester('ntpath.expandvars(%r)' % value, expected) 807 with os_helper.EnvironmentVarGuard() as env: 808 env.clear() 809 nonascii = os_helper.FS_NONASCII 810 env['spam'] = nonascii 811 env[nonascii] = 'ham' + nonascii 812 check('$spam bar', '%s bar' % nonascii) 813 check('$%s bar' % nonascii, '$%s bar' % nonascii) 814 check('${spam}bar', '%sbar' % nonascii) 815 check('${%s}bar' % nonascii, 'ham%sbar' % nonascii) 816 check('$spam}bar', '%s}bar' % nonascii) 817 check('$%s}bar' % nonascii, '$%s}bar' % nonascii) 818 check('%spam% bar', '%s bar' % nonascii) 819 check('%{}% bar'.format(nonascii), 'ham%s bar' % nonascii) 820 check('%spam%bar', '%sbar' % nonascii) 821 check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii) 822 823 def test_expanduser(self): 824 tester('ntpath.expanduser("test")', 'test') 825 826 with os_helper.EnvironmentVarGuard() as env: 827 env.clear() 828 tester('ntpath.expanduser("~test")', '~test') 829 830 env['HOMEDRIVE'] = 'C:\\' 831 env['HOMEPATH'] = 'Users\\eric' 832 env['USERNAME'] = 'eric' 833 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 834 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 835 836 del env['HOMEDRIVE'] 837 tester('ntpath.expanduser("~test")', 'Users\\test') 838 tester('ntpath.expanduser("~")', 'Users\\eric') 839 840 env.clear() 841 env['USERPROFILE'] = 'C:\\Users\\eric' 842 env['USERNAME'] = 'eric' 843 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 844 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 845 tester('ntpath.expanduser("~test\\foo\\bar")', 846 'C:\\Users\\test\\foo\\bar') 847 tester('ntpath.expanduser("~test/foo/bar")', 848 'C:\\Users\\test/foo/bar') 849 tester('ntpath.expanduser("~\\foo\\bar")', 850 'C:\\Users\\eric\\foo\\bar') 851 tester('ntpath.expanduser("~/foo/bar")', 852 'C:\\Users\\eric/foo/bar') 853 854 # bpo-36264: ignore `HOME` when set on windows 855 env.clear() 856 env['HOME'] = 'F:\\' 857 env['USERPROFILE'] = 'C:\\Users\\eric' 858 env['USERNAME'] = 'eric' 859 tester('ntpath.expanduser("~test")', 'C:\\Users\\test') 860 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 861 862 # bpo-39899: don't guess another user's home directory if 863 # `%USERNAME% != basename(%USERPROFILE%)` 864 env.clear() 865 env['USERPROFILE'] = 'C:\\Users\\eric' 866 env['USERNAME'] = 'idle' 867 tester('ntpath.expanduser("~test")', '~test') 868 tester('ntpath.expanduser("~")', 'C:\\Users\\eric') 869 870 871 872 @unittest.skipUnless(nt, "abspath requires 'nt' module") 873 def test_abspath(self): 874 tester('ntpath.abspath("C:\\")', "C:\\") 875 tester('ntpath.abspath("\\\\?\\C:////spam////eggs. . .")', "\\\\?\\C:\\spam\\eggs") 876 tester('ntpath.abspath("\\\\.\\C:////spam////eggs. . .")', "\\\\.\\C:\\spam\\eggs") 877 tester('ntpath.abspath("//spam//eggs. . .")', "\\\\spam\\eggs") 878 tester('ntpath.abspath("\\\\spam\\\\eggs. . .")', "\\\\spam\\eggs") 879 tester('ntpath.abspath("C:/spam. . .")', "C:\\spam") 880 tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam") 881 tester('ntpath.abspath("C:/nul")', "\\\\.\\nul") 882 tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul") 883 tester('ntpath.abspath("//..")', "\\\\") 884 tester('ntpath.abspath("//../")', "\\\\..\\") 885 tester('ntpath.abspath("//../..")', "\\\\..\\") 886 tester('ntpath.abspath("//../../")', "\\\\..\\..\\") 887 tester('ntpath.abspath("//../../../")', "\\\\..\\..\\") 888 tester('ntpath.abspath("//../../../..")', "\\\\..\\..\\") 889 tester('ntpath.abspath("//../../../../")', "\\\\..\\..\\") 890 tester('ntpath.abspath("//server")', "\\\\server") 891 tester('ntpath.abspath("//server/")', "\\\\server\\") 892 tester('ntpath.abspath("//server/..")', "\\\\server\\") 893 tester('ntpath.abspath("//server/../")', "\\\\server\\..\\") 894 tester('ntpath.abspath("//server/../..")', "\\\\server\\..\\") 895 tester('ntpath.abspath("//server/../../")', "\\\\server\\..\\") 896 tester('ntpath.abspath("//server/../../..")', "\\\\server\\..\\") 897 tester('ntpath.abspath("//server/../../../")', "\\\\server\\..\\") 898 tester('ntpath.abspath("//server/share")', "\\\\server\\share") 899 tester('ntpath.abspath("//server/share/")', "\\\\server\\share\\") 900 tester('ntpath.abspath("//server/share/..")', "\\\\server\\share\\") 901 tester('ntpath.abspath("//server/share/../")', "\\\\server\\share\\") 902 tester('ntpath.abspath("//server/share/../..")', "\\\\server\\share\\") 903 tester('ntpath.abspath("//server/share/../../")', "\\\\server\\share\\") 904 tester('ntpath.abspath("C:\\nul. . .")', "\\\\.\\nul") 905 tester('ntpath.abspath("//... . .")', "\\\\") 906 tester('ntpath.abspath("//.. . . .")', "\\\\") 907 tester('ntpath.abspath("//../... . .")', "\\\\..\\") 908 tester('ntpath.abspath("//../.. . . .")', "\\\\..\\") 909 with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir: # bpo-31047 910 tester('ntpath.abspath("")', cwd_dir) 911 tester('ntpath.abspath(" ")', cwd_dir + "\\ ") 912 tester('ntpath.abspath("?")', cwd_dir + "\\?") 913 drive, _ = ntpath.splitdrive(cwd_dir) 914 tester('ntpath.abspath("/abc/")', drive + "\\abc") 915 916 def test_relpath(self): 917 tester('ntpath.relpath("a")', 'a') 918 tester('ntpath.relpath(ntpath.abspath("a"))', 'a') 919 tester('ntpath.relpath("a/b")', 'a\\b') 920 tester('ntpath.relpath("../a/b")', '..\\a\\b') 921 with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir: 922 currentdir = ntpath.basename(cwd_dir) 923 tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a') 924 tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b') 925 tester('ntpath.relpath("a", "b/c")', '..\\..\\a') 926 tester('ntpath.relpath("c:/foo/bar/bat", "c:/x/y")', '..\\..\\foo\\bar\\bat') 927 tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a') 928 tester('ntpath.relpath("a", "a")', '.') 929 tester('ntpath.relpath("/foo/bar/bat", "/x/y/z")', '..\\..\\..\\foo\\bar\\bat') 930 tester('ntpath.relpath("/foo/bar/bat", "/foo/bar")', 'bat') 931 tester('ntpath.relpath("/foo/bar/bat", "/")', 'foo\\bar\\bat') 932 tester('ntpath.relpath("/", "/foo/bar/bat")', '..\\..\\..') 933 tester('ntpath.relpath("/foo/bar/bat", "/x")', '..\\foo\\bar\\bat') 934 tester('ntpath.relpath("/x", "/foo/bar/bat")', '..\\..\\..\\x') 935 tester('ntpath.relpath("/", "/")', '.') 936 tester('ntpath.relpath("/a", "/a")', '.') 937 tester('ntpath.relpath("/a/b", "/a/b")', '.') 938 tester('ntpath.relpath("c:/foo", "C:/FOO")', '.') 939 940 def test_commonpath(self): 941 def check(paths, expected): 942 tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'), 943 expected) 944 def check_error(exc, paths): 945 self.assertRaises(exc, ntpath.commonpath, paths) 946 self.assertRaises(exc, ntpath.commonpath, 947 [os.fsencode(p) for p in paths]) 948 949 self.assertRaises(ValueError, ntpath.commonpath, []) 950 check_error(ValueError, ['C:\\Program Files', 'Program Files']) 951 check_error(ValueError, ['C:\\Program Files', 'C:Program Files']) 952 check_error(ValueError, ['\\Program Files', 'Program Files']) 953 check_error(ValueError, ['Program Files', 'C:\\Program Files']) 954 check(['C:\\Program Files'], 'C:\\Program Files') 955 check(['C:\\Program Files', 'C:\\Program Files'], 'C:\\Program Files') 956 check(['C:\\Program Files\\', 'C:\\Program Files'], 957 'C:\\Program Files') 958 check(['C:\\Program Files\\', 'C:\\Program Files\\'], 959 'C:\\Program Files') 960 check(['C:\\\\Program Files', 'C:\\Program Files\\\\'], 961 'C:\\Program Files') 962 check(['C:\\.\\Program Files', 'C:\\Program Files\\.'], 963 'C:\\Program Files') 964 check(['C:\\', 'C:\\bin'], 'C:\\') 965 check(['C:\\Program Files', 'C:\\bin'], 'C:\\') 966 check(['C:\\Program Files', 'C:\\Program Files\\Bar'], 967 'C:\\Program Files') 968 check(['C:\\Program Files\\Foo', 'C:\\Program Files\\Bar'], 969 'C:\\Program Files') 970 check(['C:\\Program Files', 'C:\\Projects'], 'C:\\') 971 check(['C:\\Program Files\\', 'C:\\Projects'], 'C:\\') 972 973 check(['C:\\Program Files\\Foo', 'C:/Program Files/Bar'], 974 'C:\\Program Files') 975 check(['C:\\Program Files\\Foo', 'c:/program files/bar'], 976 'C:\\Program Files') 977 check(['c:/program files/bar', 'C:\\Program Files\\Foo'], 978 'c:\\program files') 979 980 check_error(ValueError, ['C:\\Program Files', 'D:\\Program Files']) 981 982 check(['spam'], 'spam') 983 check(['spam', 'spam'], 'spam') 984 check(['spam', 'alot'], '') 985 check(['and\\jam', 'and\\spam'], 'and') 986 check(['and\\\\jam', 'and\\spam\\\\'], 'and') 987 check(['and\\.\\jam', '.\\and\\spam'], 'and') 988 check(['and\\jam', 'and\\spam', 'alot'], '') 989 check(['and\\jam', 'and\\spam', 'and'], 'and') 990 check(['C:and\\jam', 'C:and\\spam'], 'C:and') 991 992 check([''], '') 993 check(['', 'spam\\alot'], '') 994 check_error(ValueError, ['', '\\spam\\alot']) 995 996 self.assertRaises(TypeError, ntpath.commonpath, 997 [b'C:\\Program Files', 'C:\\Program Files\\Foo']) 998 self.assertRaises(TypeError, ntpath.commonpath, 999 [b'C:\\Program Files', 'Program Files\\Foo']) 1000 self.assertRaises(TypeError, ntpath.commonpath, 1001 [b'Program Files', 'C:\\Program Files\\Foo']) 1002 self.assertRaises(TypeError, ntpath.commonpath, 1003 ['C:\\Program Files', b'C:\\Program Files\\Foo']) 1004 self.assertRaises(TypeError, ntpath.commonpath, 1005 ['C:\\Program Files', b'Program Files\\Foo']) 1006 self.assertRaises(TypeError, ntpath.commonpath, 1007 ['Program Files', b'C:\\Program Files\\Foo']) 1008 1009 @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.") 1010 def test_sameopenfile(self): 1011 with TemporaryFile() as tf1, TemporaryFile() as tf2: 1012 # Make sure the same file is really the same 1013 self.assertTrue(ntpath.sameopenfile(tf1.fileno(), tf1.fileno())) 1014 # Make sure different files are really different 1015 self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno())) 1016 # Make sure invalid values don't cause issues on win32 1017 if sys.platform == "win32": 1018 with self.assertRaises(OSError): 1019 # Invalid file descriptors shouldn't display assert 1020 # dialogs (#4804) 1021 ntpath.sameopenfile(-1, -1) 1022 1023 def test_ismount(self): 1024 self.assertTrue(ntpath.ismount("c:\\")) 1025 self.assertTrue(ntpath.ismount("C:\\")) 1026 self.assertTrue(ntpath.ismount("c:/")) 1027 self.assertTrue(ntpath.ismount("C:/")) 1028 self.assertTrue(ntpath.ismount("\\\\.\\c:\\")) 1029 self.assertTrue(ntpath.ismount("\\\\.\\C:\\")) 1030 1031 self.assertTrue(ntpath.ismount(b"c:\\")) 1032 self.assertTrue(ntpath.ismount(b"C:\\")) 1033 self.assertTrue(ntpath.ismount(b"c:/")) 1034 self.assertTrue(ntpath.ismount(b"C:/")) 1035 self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) 1036 self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) 1037 1038 with os_helper.temp_dir() as d: 1039 self.assertFalse(ntpath.ismount(d)) 1040 1041 if sys.platform == "win32": 1042 # 1043 # Make sure the current folder isn't the root folder 1044 # (or any other volume root). The drive-relative 1045 # locations below cannot then refer to mount points 1046 # 1047 test_cwd = os.getenv("SystemRoot") 1048 drive, path = ntpath.splitdrive(test_cwd) 1049 with os_helper.change_cwd(test_cwd): 1050 self.assertFalse(ntpath.ismount(drive.lower())) 1051 self.assertFalse(ntpath.ismount(drive.upper())) 1052 1053 self.assertTrue(ntpath.ismount("\\\\localhost\\c$")) 1054 self.assertTrue(ntpath.ismount("\\\\localhost\\c$\\")) 1055 1056 self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$")) 1057 self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$\\")) 1058 1059 def assertEqualCI(self, s1, s2): 1060 """Assert that two strings are equal ignoring case differences.""" 1061 self.assertEqual(s1.lower(), s2.lower()) 1062 1063 @unittest.skipUnless(nt, "OS helpers require 'nt' module") 1064 def test_nt_helpers(self): 1065 # Trivial validation that the helpers do not break, and support both 1066 # unicode and bytes (UTF-8) paths 1067 1068 executable = nt._getfinalpathname(sys.executable) 1069 1070 for path in executable, os.fsencode(executable): 1071 volume_path = nt._getvolumepathname(path) 1072 path_drive = ntpath.splitdrive(path)[0] 1073 volume_path_drive = ntpath.splitdrive(volume_path)[0] 1074 self.assertEqualCI(path_drive, volume_path_drive) 1075 1076 cap, free = nt._getdiskusage(sys.exec_prefix) 1077 self.assertGreater(cap, 0) 1078 self.assertGreater(free, 0) 1079 b_cap, b_free = nt._getdiskusage(sys.exec_prefix.encode()) 1080 # Free space may change, so only test the capacity is equal 1081 self.assertEqual(b_cap, cap) 1082 self.assertGreater(b_free, 0) 1083 1084 for path in [sys.prefix, sys.executable]: 1085 final_path = nt._getfinalpathname(path) 1086 self.assertIsInstance(final_path, str) 1087 self.assertGreater(len(final_path), 0) 1088 1089 b_final_path = nt._getfinalpathname(path.encode()) 1090 self.assertIsInstance(b_final_path, bytes) 1091 self.assertGreater(len(b_final_path), 0) 1092 1093class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase): 1094 pathmodule = ntpath 1095 attributes = ['relpath'] 1096 1097 1098class PathLikeTests(NtpathTestCase): 1099 1100 path = ntpath 1101 1102 def setUp(self): 1103 self.file_name = os_helper.TESTFN 1104 self.file_path = FakePath(os_helper.TESTFN) 1105 self.addCleanup(os_helper.unlink, self.file_name) 1106 with open(self.file_name, 'xb', 0) as file: 1107 file.write(b"test_ntpath.PathLikeTests") 1108 1109 def _check_function(self, func): 1110 self.assertPathEqual(func(self.file_path), func(self.file_name)) 1111 1112 def test_path_normcase(self): 1113 self._check_function(self.path.normcase) 1114 if sys.platform == 'win32': 1115 self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ') 1116 1117 def test_path_isabs(self): 1118 self._check_function(self.path.isabs) 1119 1120 def test_path_join(self): 1121 self.assertEqual(self.path.join('a', FakePath('b'), 'c'), 1122 self.path.join('a', 'b', 'c')) 1123 1124 def test_path_split(self): 1125 self._check_function(self.path.split) 1126 1127 def test_path_splitext(self): 1128 self._check_function(self.path.splitext) 1129 1130 def test_path_splitdrive(self): 1131 self._check_function(self.path.splitdrive) 1132 1133 def test_path_basename(self): 1134 self._check_function(self.path.basename) 1135 1136 def test_path_dirname(self): 1137 self._check_function(self.path.dirname) 1138 1139 def test_path_islink(self): 1140 self._check_function(self.path.islink) 1141 1142 def test_path_lexists(self): 1143 self._check_function(self.path.lexists) 1144 1145 def test_path_ismount(self): 1146 self._check_function(self.path.ismount) 1147 1148 def test_path_expanduser(self): 1149 self._check_function(self.path.expanduser) 1150 1151 def test_path_expandvars(self): 1152 self._check_function(self.path.expandvars) 1153 1154 def test_path_normpath(self): 1155 self._check_function(self.path.normpath) 1156 1157 def test_path_abspath(self): 1158 self._check_function(self.path.abspath) 1159 1160 def test_path_realpath(self): 1161 self._check_function(self.path.realpath) 1162 1163 def test_path_relpath(self): 1164 self._check_function(self.path.relpath) 1165 1166 def test_path_commonpath(self): 1167 common_path = self.path.commonpath([self.file_path, self.file_name]) 1168 self.assertPathEqual(common_path, self.file_name) 1169 1170 def test_path_isdir(self): 1171 self._check_function(self.path.isdir) 1172 1173 1174if __name__ == "__main__": 1175 unittest.main() 1176