1import os 2import posixpath 3import sys 4import unittest 5from posixpath import realpath, abspath, dirname, basename 6from test import test_genericpath 7from test.support import import_helper 8from test.support import os_helper 9from test.support.os_helper import FakePath 10from unittest import mock 11 12try: 13 import posix 14except ImportError: 15 posix = None 16 17 18# An absolute path to a temporary filename for testing. We can't rely on TESTFN 19# being an absolute path, so we need this. 20 21ABSTFN = abspath(os_helper.TESTFN) 22 23def skip_if_ABSTFN_contains_backslash(test): 24 """ 25 On Windows, posixpath.abspath still returns paths with backslashes 26 instead of posix forward slashes. If this is the case, several tests 27 fail, so skip them. 28 """ 29 found_backslash = '\\' in ABSTFN 30 msg = "ABSTFN is not a posix path - tests fail" 31 return [test, unittest.skip(msg)(test)][found_backslash] 32 33def safe_rmdir(dirname): 34 try: 35 os.rmdir(dirname) 36 except OSError: 37 pass 38 39class PosixPathTest(unittest.TestCase): 40 41 def setUp(self): 42 self.tearDown() 43 44 def tearDown(self): 45 for suffix in ["", "1", "2"]: 46 os_helper.unlink(os_helper.TESTFN + suffix) 47 safe_rmdir(os_helper.TESTFN + suffix) 48 49 def test_join(self): 50 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"), 51 "/bar/baz") 52 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz") 53 self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"), 54 "/foo/bar/baz/") 55 56 self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"), 57 b"/bar/baz") 58 self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"), 59 b"/foo/bar/baz") 60 self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), 61 b"/foo/bar/baz/") 62 63 def test_split(self): 64 self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) 65 self.assertEqual(posixpath.split("/"), ("/", "")) 66 self.assertEqual(posixpath.split("foo"), ("", "foo")) 67 self.assertEqual(posixpath.split("////foo"), ("////", "foo")) 68 self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar")) 69 70 self.assertEqual(posixpath.split(b"/foo/bar"), (b"/foo", b"bar")) 71 self.assertEqual(posixpath.split(b"/"), (b"/", b"")) 72 self.assertEqual(posixpath.split(b"foo"), (b"", b"foo")) 73 self.assertEqual(posixpath.split(b"////foo"), (b"////", b"foo")) 74 self.assertEqual(posixpath.split(b"//foo//bar"), (b"//foo", b"bar")) 75 76 def splitextTest(self, path, filename, ext): 77 self.assertEqual(posixpath.splitext(path), (filename, ext)) 78 self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext)) 79 self.assertEqual(posixpath.splitext("abc/" + path), 80 ("abc/" + filename, ext)) 81 self.assertEqual(posixpath.splitext("abc.def/" + path), 82 ("abc.def/" + filename, ext)) 83 self.assertEqual(posixpath.splitext("/abc.def/" + path), 84 ("/abc.def/" + filename, ext)) 85 self.assertEqual(posixpath.splitext(path + "/"), 86 (filename + ext + "/", "")) 87 88 path = bytes(path, "ASCII") 89 filename = bytes(filename, "ASCII") 90 ext = bytes(ext, "ASCII") 91 92 self.assertEqual(posixpath.splitext(path), (filename, ext)) 93 self.assertEqual(posixpath.splitext(b"/" + path), 94 (b"/" + filename, ext)) 95 self.assertEqual(posixpath.splitext(b"abc/" + path), 96 (b"abc/" + filename, ext)) 97 self.assertEqual(posixpath.splitext(b"abc.def/" + path), 98 (b"abc.def/" + filename, ext)) 99 self.assertEqual(posixpath.splitext(b"/abc.def/" + path), 100 (b"/abc.def/" + filename, ext)) 101 self.assertEqual(posixpath.splitext(path + b"/"), 102 (filename + ext + b"/", b"")) 103 104 def test_splitext(self): 105 self.splitextTest("foo.bar", "foo", ".bar") 106 self.splitextTest("foo.boo.bar", "foo.boo", ".bar") 107 self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar") 108 self.splitextTest(".csh.rc", ".csh", ".rc") 109 self.splitextTest("nodots", "nodots", "") 110 self.splitextTest(".cshrc", ".cshrc", "") 111 self.splitextTest("...manydots", "...manydots", "") 112 self.splitextTest("...manydots.ext", "...manydots", ".ext") 113 self.splitextTest(".", ".", "") 114 self.splitextTest("..", "..", "") 115 self.splitextTest("........", "........", "") 116 self.splitextTest("", "", "") 117 118 def test_isabs(self): 119 self.assertIs(posixpath.isabs(""), False) 120 self.assertIs(posixpath.isabs("/"), True) 121 self.assertIs(posixpath.isabs("/foo"), True) 122 self.assertIs(posixpath.isabs("/foo/bar"), True) 123 self.assertIs(posixpath.isabs("foo/bar"), False) 124 125 self.assertIs(posixpath.isabs(b""), False) 126 self.assertIs(posixpath.isabs(b"/"), True) 127 self.assertIs(posixpath.isabs(b"/foo"), True) 128 self.assertIs(posixpath.isabs(b"/foo/bar"), True) 129 self.assertIs(posixpath.isabs(b"foo/bar"), False) 130 131 def test_basename(self): 132 self.assertEqual(posixpath.basename("/foo/bar"), "bar") 133 self.assertEqual(posixpath.basename("/"), "") 134 self.assertEqual(posixpath.basename("foo"), "foo") 135 self.assertEqual(posixpath.basename("////foo"), "foo") 136 self.assertEqual(posixpath.basename("//foo//bar"), "bar") 137 138 self.assertEqual(posixpath.basename(b"/foo/bar"), b"bar") 139 self.assertEqual(posixpath.basename(b"/"), b"") 140 self.assertEqual(posixpath.basename(b"foo"), b"foo") 141 self.assertEqual(posixpath.basename(b"////foo"), b"foo") 142 self.assertEqual(posixpath.basename(b"//foo//bar"), b"bar") 143 144 def test_dirname(self): 145 self.assertEqual(posixpath.dirname("/foo/bar"), "/foo") 146 self.assertEqual(posixpath.dirname("/"), "/") 147 self.assertEqual(posixpath.dirname("foo"), "") 148 self.assertEqual(posixpath.dirname("////foo"), "////") 149 self.assertEqual(posixpath.dirname("//foo//bar"), "//foo") 150 151 self.assertEqual(posixpath.dirname(b"/foo/bar"), b"/foo") 152 self.assertEqual(posixpath.dirname(b"/"), b"/") 153 self.assertEqual(posixpath.dirname(b"foo"), b"") 154 self.assertEqual(posixpath.dirname(b"////foo"), b"////") 155 self.assertEqual(posixpath.dirname(b"//foo//bar"), b"//foo") 156 157 def test_islink(self): 158 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False) 159 self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), False) 160 161 with open(os_helper.TESTFN + "1", "wb") as f: 162 f.write(b"foo") 163 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False) 164 165 if os_helper.can_symlink(): 166 os.symlink(os_helper.TESTFN + "1", os_helper.TESTFN + "2") 167 self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True) 168 os.remove(os_helper.TESTFN + "1") 169 self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True) 170 self.assertIs(posixpath.exists(os_helper.TESTFN + "2"), False) 171 self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), True) 172 173 self.assertIs(posixpath.islink(os_helper.TESTFN + "\udfff"), False) 174 self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\xff"), False) 175 self.assertIs(posixpath.islink(os_helper.TESTFN + "\x00"), False) 176 self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\x00"), False) 177 178 def test_ismount(self): 179 self.assertIs(posixpath.ismount("/"), True) 180 self.assertIs(posixpath.ismount(b"/"), True) 181 self.assertIs(posixpath.ismount(FakePath("/")), True) 182 self.assertIs(posixpath.ismount(FakePath(b"/")), True) 183 184 def test_ismount_non_existent(self): 185 # Non-existent mountpoint. 186 self.assertIs(posixpath.ismount(ABSTFN), False) 187 try: 188 os.mkdir(ABSTFN) 189 self.assertIs(posixpath.ismount(ABSTFN), False) 190 finally: 191 safe_rmdir(ABSTFN) 192 193 self.assertIs(posixpath.ismount('/\udfff'), False) 194 self.assertIs(posixpath.ismount(b'/\xff'), False) 195 self.assertIs(posixpath.ismount('/\x00'), False) 196 self.assertIs(posixpath.ismount(b'/\x00'), False) 197 198 @os_helper.skip_unless_symlink 199 def test_ismount_symlinks(self): 200 # Symlinks are never mountpoints. 201 try: 202 os.symlink("/", ABSTFN) 203 self.assertIs(posixpath.ismount(ABSTFN), False) 204 finally: 205 os.unlink(ABSTFN) 206 207 @unittest.skipIf(posix is None, "Test requires posix module") 208 def test_ismount_different_device(self): 209 # Simulate the path being on a different device from its parent by 210 # mocking out st_dev. 211 save_lstat = os.lstat 212 def fake_lstat(path): 213 st_ino = 0 214 st_dev = 0 215 if path == ABSTFN: 216 st_dev = 1 217 st_ino = 1 218 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0)) 219 try: 220 os.lstat = fake_lstat 221 self.assertIs(posixpath.ismount(ABSTFN), True) 222 finally: 223 os.lstat = save_lstat 224 225 @unittest.skipIf(posix is None, "Test requires posix module") 226 def test_ismount_directory_not_readable(self): 227 # issue #2466: Simulate ismount run on a directory that is not 228 # readable, which used to return False. 229 save_lstat = os.lstat 230 def fake_lstat(path): 231 st_ino = 0 232 st_dev = 0 233 if path.startswith(ABSTFN) and path != ABSTFN: 234 # ismount tries to read something inside the ABSTFN directory; 235 # simulate this being forbidden (no read permission). 236 raise OSError("Fake [Errno 13] Permission denied") 237 if path == ABSTFN: 238 st_dev = 1 239 st_ino = 1 240 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0)) 241 try: 242 os.lstat = fake_lstat 243 self.assertIs(posixpath.ismount(ABSTFN), True) 244 finally: 245 os.lstat = save_lstat 246 247 def test_expanduser(self): 248 self.assertEqual(posixpath.expanduser("foo"), "foo") 249 self.assertEqual(posixpath.expanduser(b"foo"), b"foo") 250 251 def test_expanduser_home_envvar(self): 252 with os_helper.EnvironmentVarGuard() as env: 253 env['HOME'] = '/home/victor' 254 self.assertEqual(posixpath.expanduser("~"), "/home/victor") 255 256 # expanduser() strips trailing slash 257 env['HOME'] = '/home/victor/' 258 self.assertEqual(posixpath.expanduser("~"), "/home/victor") 259 260 for home in '/', '', '//', '///': 261 with self.subTest(home=home): 262 env['HOME'] = home 263 self.assertEqual(posixpath.expanduser("~"), "/") 264 self.assertEqual(posixpath.expanduser("~/"), "/") 265 self.assertEqual(posixpath.expanduser("~/foo"), "/foo") 266 267 @unittest.skipIf(sys.platform == "vxworks", 268 "no home directory on VxWorks") 269 def test_expanduser_pwd(self): 270 pwd = import_helper.import_module('pwd') 271 272 self.assertIsInstance(posixpath.expanduser("~/"), str) 273 self.assertIsInstance(posixpath.expanduser(b"~/"), bytes) 274 275 # if home directory == root directory, this test makes no sense 276 if posixpath.expanduser("~") != '/': 277 self.assertEqual( 278 posixpath.expanduser("~") + "/", 279 posixpath.expanduser("~/") 280 ) 281 self.assertEqual( 282 posixpath.expanduser(b"~") + b"/", 283 posixpath.expanduser(b"~/") 284 ) 285 self.assertIsInstance(posixpath.expanduser("~root/"), str) 286 self.assertIsInstance(posixpath.expanduser("~foo/"), str) 287 self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes) 288 self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes) 289 290 with os_helper.EnvironmentVarGuard() as env: 291 # expanduser should fall back to using the password database 292 del env['HOME'] 293 294 home = pwd.getpwuid(os.getuid()).pw_dir 295 # $HOME can end with a trailing /, so strip it (see #17809) 296 home = home.rstrip("/") or '/' 297 self.assertEqual(posixpath.expanduser("~"), home) 298 299 # bpo-10496: If the HOME environment variable is not set and the 300 # user (current identifier or name in the path) doesn't exist in 301 # the password database (pwd.getuid() or pwd.getpwnam() fail), 302 # expanduser() must return the path unchanged. 303 with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError), \ 304 mock.patch.object(pwd, 'getpwnam', side_effect=KeyError): 305 for path in ('~', '~/.local', '~vstinner/'): 306 self.assertEqual(posixpath.expanduser(path), path) 307 308 NORMPATH_CASES = [ 309 ("", "."), 310 ("/", "/"), 311 ("/.", "/"), 312 ("/./", "/"), 313 ("/.//.", "/"), 314 ("/foo", "/foo"), 315 ("/foo/bar", "/foo/bar"), 316 ("//", "//"), 317 ("///", "/"), 318 ("///foo/.//bar//", "/foo/bar"), 319 ("///foo/.//bar//.//..//.//baz///", "/foo/baz"), 320 ("///..//./foo/.//bar", "/foo/bar"), 321 (".", "."), 322 (".//.", "."), 323 ("..", ".."), 324 ("../", ".."), 325 ("../foo", "../foo"), 326 ("../../foo", "../../foo"), 327 ("../foo/../bar", "../bar"), 328 ("../../foo/../bar/./baz/boom/..", "../../bar/baz"), 329 ("/..", "/"), 330 ("/..", "/"), 331 ("/../", "/"), 332 ("/..//", "/"), 333 ("//.", "//"), 334 ("//..", "//"), 335 ("//...", "//..."), 336 ("//../foo", "//foo"), 337 ("//../../foo", "//foo"), 338 ("/../foo", "/foo"), 339 ("/../../foo", "/foo"), 340 ("/../foo/../", "/"), 341 ("/../foo/../bar", "/bar"), 342 ("/../../foo/../bar/./baz/boom/..", "/bar/baz"), 343 ("/../../foo/../bar/./baz/boom/.", "/bar/baz/boom"), 344 ("foo/../bar/baz", "bar/baz"), 345 ("foo/../../bar/baz", "../bar/baz"), 346 ("foo/../../../bar/baz", "../../bar/baz"), 347 ("foo///../bar/.././../baz/boom", "../baz/boom"), 348 ("foo/bar/../..///../../baz/boom", "../../baz/boom"), 349 ("/foo/..", "/"), 350 ("/foo/../..", "/"), 351 ("//foo/..", "//"), 352 ("//foo/../..", "//"), 353 ("///foo/..", "/"), 354 ("///foo/../..", "/"), 355 ("////foo/..", "/"), 356 ("/////foo/..", "/"), 357 ] 358 359 def test_normpath(self): 360 for path, expected in self.NORMPATH_CASES: 361 with self.subTest(path): 362 result = posixpath.normpath(path) 363 self.assertEqual(result, expected) 364 365 path = path.encode('utf-8') 366 expected = expected.encode('utf-8') 367 with self.subTest(path, type=bytes): 368 result = posixpath.normpath(path) 369 self.assertEqual(result, expected) 370 371 @skip_if_ABSTFN_contains_backslash 372 def test_realpath_curdir(self): 373 self.assertEqual(realpath('.'), os.getcwd()) 374 self.assertEqual(realpath('./.'), os.getcwd()) 375 self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd()) 376 377 self.assertEqual(realpath(b'.'), os.getcwdb()) 378 self.assertEqual(realpath(b'./.'), os.getcwdb()) 379 self.assertEqual(realpath(b'/'.join([b'.'] * 100)), os.getcwdb()) 380 381 @skip_if_ABSTFN_contains_backslash 382 def test_realpath_pardir(self): 383 self.assertEqual(realpath('..'), dirname(os.getcwd())) 384 self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd()))) 385 self.assertEqual(realpath('/'.join(['..'] * 100)), '/') 386 387 self.assertEqual(realpath(b'..'), dirname(os.getcwdb())) 388 self.assertEqual(realpath(b'../..'), dirname(dirname(os.getcwdb()))) 389 self.assertEqual(realpath(b'/'.join([b'..'] * 100)), b'/') 390 391 @os_helper.skip_unless_symlink 392 @skip_if_ABSTFN_contains_backslash 393 def test_realpath_basic(self): 394 # Basic operation. 395 try: 396 os.symlink(ABSTFN+"1", ABSTFN) 397 self.assertEqual(realpath(ABSTFN), ABSTFN+"1") 398 finally: 399 os_helper.unlink(ABSTFN) 400 401 @os_helper.skip_unless_symlink 402 @skip_if_ABSTFN_contains_backslash 403 def test_realpath_strict(self): 404 # Bug #43757: raise FileNotFoundError in strict mode if we encounter 405 # a path that does not exist. 406 try: 407 os.symlink(ABSTFN+"1", ABSTFN) 408 self.assertRaises(FileNotFoundError, realpath, ABSTFN, strict=True) 409 self.assertRaises(FileNotFoundError, realpath, ABSTFN + "2", strict=True) 410 finally: 411 os_helper.unlink(ABSTFN) 412 413 @os_helper.skip_unless_symlink 414 @skip_if_ABSTFN_contains_backslash 415 def test_realpath_relative(self): 416 try: 417 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN) 418 self.assertEqual(realpath(ABSTFN), ABSTFN+"1") 419 finally: 420 os_helper.unlink(ABSTFN) 421 422 @os_helper.skip_unless_symlink 423 @skip_if_ABSTFN_contains_backslash 424 def test_realpath_symlink_loops(self): 425 # Bug #930024, return the path unchanged if we get into an infinite 426 # symlink loop in non-strict mode (default). 427 try: 428 os.symlink(ABSTFN, ABSTFN) 429 self.assertEqual(realpath(ABSTFN), ABSTFN) 430 431 os.symlink(ABSTFN+"1", ABSTFN+"2") 432 os.symlink(ABSTFN+"2", ABSTFN+"1") 433 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1") 434 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2") 435 436 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x") 437 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN)) 438 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x") 439 os.symlink(ABSTFN+"x", ABSTFN+"y") 440 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"), 441 ABSTFN + "y") 442 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"), 443 ABSTFN + "1") 444 445 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a") 446 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b") 447 448 os.symlink("../" + basename(dirname(ABSTFN)) + "/" + 449 basename(ABSTFN) + "c", ABSTFN+"c") 450 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c") 451 452 # Test using relative path as well. 453 with os_helper.change_cwd(dirname(ABSTFN)): 454 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN) 455 finally: 456 os_helper.unlink(ABSTFN) 457 os_helper.unlink(ABSTFN+"1") 458 os_helper.unlink(ABSTFN+"2") 459 os_helper.unlink(ABSTFN+"y") 460 os_helper.unlink(ABSTFN+"c") 461 os_helper.unlink(ABSTFN+"a") 462 463 @os_helper.skip_unless_symlink 464 @skip_if_ABSTFN_contains_backslash 465 def test_realpath_symlink_loops_strict(self): 466 # Bug #43757, raise OSError if we get into an infinite symlink loop in 467 # strict mode. 468 try: 469 os.symlink(ABSTFN, ABSTFN) 470 self.assertRaises(OSError, realpath, ABSTFN, strict=True) 471 472 os.symlink(ABSTFN+"1", ABSTFN+"2") 473 os.symlink(ABSTFN+"2", ABSTFN+"1") 474 self.assertRaises(OSError, realpath, ABSTFN+"1", strict=True) 475 self.assertRaises(OSError, realpath, ABSTFN+"2", strict=True) 476 477 self.assertRaises(OSError, realpath, ABSTFN+"1/x", strict=True) 478 self.assertRaises(OSError, realpath, ABSTFN+"1/..", strict=True) 479 self.assertRaises(OSError, realpath, ABSTFN+"1/../x", strict=True) 480 os.symlink(ABSTFN+"x", ABSTFN+"y") 481 self.assertRaises(OSError, realpath, 482 ABSTFN+"1/../" + basename(ABSTFN) + "y", strict=True) 483 self.assertRaises(OSError, realpath, 484 ABSTFN+"1/../" + basename(ABSTFN) + "1", strict=True) 485 486 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a") 487 self.assertRaises(OSError, realpath, ABSTFN+"a", strict=True) 488 489 os.symlink("../" + basename(dirname(ABSTFN)) + "/" + 490 basename(ABSTFN) + "c", ABSTFN+"c") 491 self.assertRaises(OSError, realpath, ABSTFN+"c", strict=True) 492 493 # Test using relative path as well. 494 with os_helper.change_cwd(dirname(ABSTFN)): 495 self.assertRaises(OSError, realpath, basename(ABSTFN), strict=True) 496 finally: 497 os_helper.unlink(ABSTFN) 498 os_helper.unlink(ABSTFN+"1") 499 os_helper.unlink(ABSTFN+"2") 500 os_helper.unlink(ABSTFN+"y") 501 os_helper.unlink(ABSTFN+"c") 502 os_helper.unlink(ABSTFN+"a") 503 504 @os_helper.skip_unless_symlink 505 @skip_if_ABSTFN_contains_backslash 506 def test_realpath_repeated_indirect_symlinks(self): 507 # Issue #6975. 508 try: 509 os.mkdir(ABSTFN) 510 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self') 511 os.symlink('self/self/self', ABSTFN + '/link') 512 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN) 513 finally: 514 os_helper.unlink(ABSTFN + '/self') 515 os_helper.unlink(ABSTFN + '/link') 516 safe_rmdir(ABSTFN) 517 518 @os_helper.skip_unless_symlink 519 @skip_if_ABSTFN_contains_backslash 520 def test_realpath_deep_recursion(self): 521 depth = 10 522 try: 523 os.mkdir(ABSTFN) 524 for i in range(depth): 525 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1)) 526 os.symlink('.', ABSTFN + '/0') 527 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN) 528 529 # Test using relative path as well. 530 with os_helper.change_cwd(ABSTFN): 531 self.assertEqual(realpath('%d' % depth), ABSTFN) 532 finally: 533 for i in range(depth + 1): 534 os_helper.unlink(ABSTFN + '/%d' % i) 535 safe_rmdir(ABSTFN) 536 537 @os_helper.skip_unless_symlink 538 @skip_if_ABSTFN_contains_backslash 539 def test_realpath_resolve_parents(self): 540 # We also need to resolve any symlinks in the parents of a relative 541 # path passed to realpath. E.g.: current working directory is 542 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call 543 # realpath("a"). This should return /usr/share/doc/a/. 544 try: 545 os.mkdir(ABSTFN) 546 os.mkdir(ABSTFN + "/y") 547 os.symlink(ABSTFN + "/y", ABSTFN + "/k") 548 549 with os_helper.change_cwd(ABSTFN + "/k"): 550 self.assertEqual(realpath("a"), ABSTFN + "/y/a") 551 finally: 552 os_helper.unlink(ABSTFN + "/k") 553 safe_rmdir(ABSTFN + "/y") 554 safe_rmdir(ABSTFN) 555 556 @os_helper.skip_unless_symlink 557 @skip_if_ABSTFN_contains_backslash 558 def test_realpath_resolve_before_normalizing(self): 559 # Bug #990669: Symbolic links should be resolved before we 560 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y' 561 # in the following hierarchy: 562 # a/k/y 563 # 564 # and a symbolic link 'link-y' pointing to 'y' in directory 'a', 565 # then realpath("link-y/..") should return 'k', not 'a'. 566 try: 567 os.mkdir(ABSTFN) 568 os.mkdir(ABSTFN + "/k") 569 os.mkdir(ABSTFN + "/k/y") 570 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y") 571 572 # Absolute path. 573 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k") 574 # Relative path. 575 with os_helper.change_cwd(dirname(ABSTFN)): 576 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."), 577 ABSTFN + "/k") 578 finally: 579 os_helper.unlink(ABSTFN + "/link-y") 580 safe_rmdir(ABSTFN + "/k/y") 581 safe_rmdir(ABSTFN + "/k") 582 safe_rmdir(ABSTFN) 583 584 @os_helper.skip_unless_symlink 585 @skip_if_ABSTFN_contains_backslash 586 def test_realpath_resolve_first(self): 587 # Bug #1213894: The first component of the path, if not absolute, 588 # must be resolved too. 589 590 try: 591 os.mkdir(ABSTFN) 592 os.mkdir(ABSTFN + "/k") 593 os.symlink(ABSTFN, ABSTFN + "link") 594 with os_helper.change_cwd(dirname(ABSTFN)): 595 base = basename(ABSTFN) 596 self.assertEqual(realpath(base + "link"), ABSTFN) 597 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k") 598 finally: 599 os_helper.unlink(ABSTFN + "link") 600 safe_rmdir(ABSTFN + "/k") 601 safe_rmdir(ABSTFN) 602 603 def test_relpath(self): 604 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar") 605 try: 606 curdir = os.path.split(os.getcwd())[-1] 607 self.assertRaises(ValueError, posixpath.relpath, "") 608 self.assertEqual(posixpath.relpath("a"), "a") 609 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a") 610 self.assertEqual(posixpath.relpath("a/b"), "a/b") 611 self.assertEqual(posixpath.relpath("../a/b"), "../a/b") 612 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a") 613 self.assertEqual(posixpath.relpath("a/b", "../c"), 614 "../"+curdir+"/a/b") 615 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") 616 self.assertEqual(posixpath.relpath("a", "a"), ".") 617 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat') 618 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat') 619 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat') 620 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..') 621 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat') 622 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x') 623 self.assertEqual(posixpath.relpath("/", "/"), '.') 624 self.assertEqual(posixpath.relpath("/a", "/a"), '.') 625 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.') 626 finally: 627 os.getcwd = real_getcwd 628 629 def test_relpath_bytes(self): 630 (real_getcwdb, os.getcwdb) = (os.getcwdb, lambda: br"/home/user/bar") 631 try: 632 curdir = os.path.split(os.getcwdb())[-1] 633 self.assertRaises(ValueError, posixpath.relpath, b"") 634 self.assertEqual(posixpath.relpath(b"a"), b"a") 635 self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a") 636 self.assertEqual(posixpath.relpath(b"a/b"), b"a/b") 637 self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b") 638 self.assertEqual(posixpath.relpath(b"a", b"../b"), 639 b"../"+curdir+b"/a") 640 self.assertEqual(posixpath.relpath(b"a/b", b"../c"), 641 b"../"+curdir+b"/a/b") 642 self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a") 643 self.assertEqual(posixpath.relpath(b"a", b"a"), b".") 644 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat') 645 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat') 646 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat') 647 self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..') 648 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat') 649 self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x') 650 self.assertEqual(posixpath.relpath(b"/", b"/"), b'.') 651 self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.') 652 self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.') 653 654 self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str") 655 self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes") 656 finally: 657 os.getcwdb = real_getcwdb 658 659 def test_commonpath(self): 660 def check(paths, expected): 661 self.assertEqual(posixpath.commonpath(paths), expected) 662 self.assertEqual(posixpath.commonpath([os.fsencode(p) for p in paths]), 663 os.fsencode(expected)) 664 def check_error(exc, paths): 665 self.assertRaises(exc, posixpath.commonpath, paths) 666 self.assertRaises(exc, posixpath.commonpath, 667 [os.fsencode(p) for p in paths]) 668 669 self.assertRaises(ValueError, posixpath.commonpath, []) 670 check_error(ValueError, ['/usr', 'usr']) 671 check_error(ValueError, ['usr', '/usr']) 672 673 check(['/usr/local'], '/usr/local') 674 check(['/usr/local', '/usr/local'], '/usr/local') 675 check(['/usr/local/', '/usr/local'], '/usr/local') 676 check(['/usr/local/', '/usr/local/'], '/usr/local') 677 check(['/usr//local', '//usr/local'], '/usr/local') 678 check(['/usr/./local', '/./usr/local'], '/usr/local') 679 check(['/', '/dev'], '/') 680 check(['/usr', '/dev'], '/') 681 check(['/usr/lib/', '/usr/lib/python3'], '/usr/lib') 682 check(['/usr/lib/', '/usr/lib64/'], '/usr') 683 684 check(['/usr/lib', '/usr/lib64'], '/usr') 685 check(['/usr/lib/', '/usr/lib64'], '/usr') 686 687 check(['spam'], 'spam') 688 check(['spam', 'spam'], 'spam') 689 check(['spam', 'alot'], '') 690 check(['and/jam', 'and/spam'], 'and') 691 check(['and//jam', 'and/spam//'], 'and') 692 check(['and/./jam', './and/spam'], 'and') 693 check(['and/jam', 'and/spam', 'alot'], '') 694 check(['and/jam', 'and/spam', 'and'], 'and') 695 696 check([''], '') 697 check(['', 'spam/alot'], '') 698 check_error(ValueError, ['', '/spam/alot']) 699 700 self.assertRaises(TypeError, posixpath.commonpath, 701 [b'/usr/lib/', '/usr/lib/python3']) 702 self.assertRaises(TypeError, posixpath.commonpath, 703 [b'/usr/lib/', 'usr/lib/python3']) 704 self.assertRaises(TypeError, posixpath.commonpath, 705 [b'usr/lib/', '/usr/lib/python3']) 706 self.assertRaises(TypeError, posixpath.commonpath, 707 ['/usr/lib/', b'/usr/lib/python3']) 708 self.assertRaises(TypeError, posixpath.commonpath, 709 ['/usr/lib/', b'usr/lib/python3']) 710 self.assertRaises(TypeError, posixpath.commonpath, 711 ['usr/lib/', b'/usr/lib/python3']) 712 713 714class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase): 715 pathmodule = posixpath 716 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat'] 717 718 719class PathLikeTests(unittest.TestCase): 720 721 path = posixpath 722 723 def setUp(self): 724 self.file_name = os_helper.TESTFN 725 self.file_path = FakePath(os_helper.TESTFN) 726 self.addCleanup(os_helper.unlink, self.file_name) 727 with open(self.file_name, 'xb', 0) as file: 728 file.write(b"test_posixpath.PathLikeTests") 729 730 def assertPathEqual(self, func): 731 self.assertEqual(func(self.file_path), func(self.file_name)) 732 733 def test_path_normcase(self): 734 self.assertPathEqual(self.path.normcase) 735 736 def test_path_isabs(self): 737 self.assertPathEqual(self.path.isabs) 738 739 def test_path_join(self): 740 self.assertEqual(self.path.join('a', FakePath('b'), 'c'), 741 self.path.join('a', 'b', 'c')) 742 743 def test_path_split(self): 744 self.assertPathEqual(self.path.split) 745 746 def test_path_splitext(self): 747 self.assertPathEqual(self.path.splitext) 748 749 def test_path_splitdrive(self): 750 self.assertPathEqual(self.path.splitdrive) 751 752 def test_path_basename(self): 753 self.assertPathEqual(self.path.basename) 754 755 def test_path_dirname(self): 756 self.assertPathEqual(self.path.dirname) 757 758 def test_path_islink(self): 759 self.assertPathEqual(self.path.islink) 760 761 def test_path_lexists(self): 762 self.assertPathEqual(self.path.lexists) 763 764 def test_path_ismount(self): 765 self.assertPathEqual(self.path.ismount) 766 767 def test_path_expanduser(self): 768 self.assertPathEqual(self.path.expanduser) 769 770 def test_path_expandvars(self): 771 self.assertPathEqual(self.path.expandvars) 772 773 def test_path_normpath(self): 774 self.assertPathEqual(self.path.normpath) 775 776 def test_path_abspath(self): 777 self.assertPathEqual(self.path.abspath) 778 779 def test_path_realpath(self): 780 self.assertPathEqual(self.path.realpath) 781 782 def test_path_relpath(self): 783 self.assertPathEqual(self.path.relpath) 784 785 def test_path_commonpath(self): 786 common_path = self.path.commonpath([self.file_path, self.file_name]) 787 self.assertEqual(common_path, self.file_name) 788 789 790if __name__=="__main__": 791 unittest.main() 792