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 182 def test_ismount_non_existent(self): 183 # Non-existent mountpoint. 184 self.assertIs(posixpath.ismount(ABSTFN), False) 185 try: 186 os.mkdir(ABSTFN) 187 self.assertIs(posixpath.ismount(ABSTFN), False) 188 finally: 189 safe_rmdir(ABSTFN) 190 191 self.assertIs(posixpath.ismount('/\udfff'), False) 192 self.assertIs(posixpath.ismount(b'/\xff'), False) 193 self.assertIs(posixpath.ismount('/\x00'), False) 194 self.assertIs(posixpath.ismount(b'/\x00'), False) 195 196 @unittest.skipUnless(os_helper.can_symlink(), 197 "Test requires symlink support") 198 def test_ismount_symlinks(self): 199 # Symlinks are never mountpoints. 200 try: 201 os.symlink("/", ABSTFN) 202 self.assertIs(posixpath.ismount(ABSTFN), False) 203 finally: 204 os.unlink(ABSTFN) 205 206 @unittest.skipIf(posix is None, "Test requires posix module") 207 def test_ismount_different_device(self): 208 # Simulate the path being on a different device from its parent by 209 # mocking out st_dev. 210 save_lstat = os.lstat 211 def fake_lstat(path): 212 st_ino = 0 213 st_dev = 0 214 if path == ABSTFN: 215 st_dev = 1 216 st_ino = 1 217 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0)) 218 try: 219 os.lstat = fake_lstat 220 self.assertIs(posixpath.ismount(ABSTFN), True) 221 finally: 222 os.lstat = save_lstat 223 224 @unittest.skipIf(posix is None, "Test requires posix module") 225 def test_ismount_directory_not_readable(self): 226 # issue #2466: Simulate ismount run on a directory that is not 227 # readable, which used to return False. 228 save_lstat = os.lstat 229 def fake_lstat(path): 230 st_ino = 0 231 st_dev = 0 232 if path.startswith(ABSTFN) and path != ABSTFN: 233 # ismount tries to read something inside the ABSTFN directory; 234 # simulate this being forbidden (no read permission). 235 raise OSError("Fake [Errno 13] Permission denied") 236 if path == ABSTFN: 237 st_dev = 1 238 st_ino = 1 239 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0)) 240 try: 241 os.lstat = fake_lstat 242 self.assertIs(posixpath.ismount(ABSTFN), True) 243 finally: 244 os.lstat = save_lstat 245 246 def test_expanduser(self): 247 self.assertEqual(posixpath.expanduser("foo"), "foo") 248 self.assertEqual(posixpath.expanduser(b"foo"), b"foo") 249 250 def test_expanduser_home_envvar(self): 251 with os_helper.EnvironmentVarGuard() as env: 252 env['HOME'] = '/home/victor' 253 self.assertEqual(posixpath.expanduser("~"), "/home/victor") 254 255 # expanduser() strips trailing slash 256 env['HOME'] = '/home/victor/' 257 self.assertEqual(posixpath.expanduser("~"), "/home/victor") 258 259 for home in '/', '', '//', '///': 260 with self.subTest(home=home): 261 env['HOME'] = home 262 self.assertEqual(posixpath.expanduser("~"), "/") 263 self.assertEqual(posixpath.expanduser("~/"), "/") 264 self.assertEqual(posixpath.expanduser("~/foo"), "/foo") 265 266 @unittest.skipIf(sys.platform == "vxworks", 267 "no home directory on VxWorks") 268 def test_expanduser_pwd(self): 269 pwd = import_helper.import_module('pwd') 270 271 self.assertIsInstance(posixpath.expanduser("~/"), str) 272 self.assertIsInstance(posixpath.expanduser(b"~/"), bytes) 273 274 # if home directory == root directory, this test makes no sense 275 if posixpath.expanduser("~") != '/': 276 self.assertEqual( 277 posixpath.expanduser("~") + "/", 278 posixpath.expanduser("~/") 279 ) 280 self.assertEqual( 281 posixpath.expanduser(b"~") + b"/", 282 posixpath.expanduser(b"~/") 283 ) 284 self.assertIsInstance(posixpath.expanduser("~root/"), str) 285 self.assertIsInstance(posixpath.expanduser("~foo/"), str) 286 self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes) 287 self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes) 288 289 with os_helper.EnvironmentVarGuard() as env: 290 # expanduser should fall back to using the password database 291 del env['HOME'] 292 293 home = pwd.getpwuid(os.getuid()).pw_dir 294 # $HOME can end with a trailing /, so strip it (see #17809) 295 home = home.rstrip("/") or '/' 296 self.assertEqual(posixpath.expanduser("~"), home) 297 298 # bpo-10496: If the HOME environment variable is not set and the 299 # user (current identifier or name in the path) doesn't exist in 300 # the password database (pwd.getuid() or pwd.getpwnam() fail), 301 # expanduser() must return the path unchanged. 302 with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError), \ 303 mock.patch.object(pwd, 'getpwnam', side_effect=KeyError): 304 for path in ('~', '~/.local', '~vstinner/'): 305 self.assertEqual(posixpath.expanduser(path), path) 306 307 def test_normpath(self): 308 self.assertEqual(posixpath.normpath(""), ".") 309 self.assertEqual(posixpath.normpath("/"), "/") 310 self.assertEqual(posixpath.normpath("//"), "//") 311 self.assertEqual(posixpath.normpath("///"), "/") 312 self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar") 313 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), 314 "/foo/baz") 315 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar") 316 317 self.assertEqual(posixpath.normpath(b""), b".") 318 self.assertEqual(posixpath.normpath(b"/"), b"/") 319 self.assertEqual(posixpath.normpath(b"//"), b"//") 320 self.assertEqual(posixpath.normpath(b"///"), b"/") 321 self.assertEqual(posixpath.normpath(b"///foo/.//bar//"), b"/foo/bar") 322 self.assertEqual(posixpath.normpath(b"///foo/.//bar//.//..//.//baz"), 323 b"/foo/baz") 324 self.assertEqual(posixpath.normpath(b"///..//./foo/.//bar"), 325 b"/foo/bar") 326 327 @skip_if_ABSTFN_contains_backslash 328 def test_realpath_curdir(self): 329 self.assertEqual(realpath('.'), os.getcwd()) 330 self.assertEqual(realpath('./.'), os.getcwd()) 331 self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd()) 332 333 self.assertEqual(realpath(b'.'), os.getcwdb()) 334 self.assertEqual(realpath(b'./.'), os.getcwdb()) 335 self.assertEqual(realpath(b'/'.join([b'.'] * 100)), os.getcwdb()) 336 337 @skip_if_ABSTFN_contains_backslash 338 def test_realpath_pardir(self): 339 self.assertEqual(realpath('..'), dirname(os.getcwd())) 340 self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd()))) 341 self.assertEqual(realpath('/'.join(['..'] * 100)), '/') 342 343 self.assertEqual(realpath(b'..'), dirname(os.getcwdb())) 344 self.assertEqual(realpath(b'../..'), dirname(dirname(os.getcwdb()))) 345 self.assertEqual(realpath(b'/'.join([b'..'] * 100)), b'/') 346 347 @unittest.skipUnless(hasattr(os, "symlink"), 348 "Missing symlink implementation") 349 @skip_if_ABSTFN_contains_backslash 350 def test_realpath_basic(self): 351 # Basic operation. 352 try: 353 os.symlink(ABSTFN+"1", ABSTFN) 354 self.assertEqual(realpath(ABSTFN), ABSTFN+"1") 355 finally: 356 os_helper.unlink(ABSTFN) 357 358 @unittest.skipUnless(hasattr(os, "symlink"), 359 "Missing symlink implementation") 360 @skip_if_ABSTFN_contains_backslash 361 def test_realpath_strict(self): 362 # Bug #43757: raise FileNotFoundError in strict mode if we encounter 363 # a path that does not exist. 364 try: 365 os.symlink(ABSTFN+"1", ABSTFN) 366 self.assertRaises(FileNotFoundError, realpath, ABSTFN, strict=True) 367 self.assertRaises(FileNotFoundError, realpath, ABSTFN + "2", strict=True) 368 finally: 369 os_helper.unlink(ABSTFN) 370 371 @unittest.skipUnless(hasattr(os, "symlink"), 372 "Missing symlink implementation") 373 @skip_if_ABSTFN_contains_backslash 374 def test_realpath_relative(self): 375 try: 376 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN) 377 self.assertEqual(realpath(ABSTFN), ABSTFN+"1") 378 finally: 379 os_helper.unlink(ABSTFN) 380 381 @unittest.skipUnless(hasattr(os, "symlink"), 382 "Missing symlink implementation") 383 @skip_if_ABSTFN_contains_backslash 384 def test_realpath_symlink_loops(self): 385 # Bug #930024, return the path unchanged if we get into an infinite 386 # symlink loop in non-strict mode (default). 387 try: 388 os.symlink(ABSTFN, ABSTFN) 389 self.assertEqual(realpath(ABSTFN), ABSTFN) 390 391 os.symlink(ABSTFN+"1", ABSTFN+"2") 392 os.symlink(ABSTFN+"2", ABSTFN+"1") 393 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1") 394 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2") 395 396 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x") 397 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN)) 398 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x") 399 os.symlink(ABSTFN+"x", ABSTFN+"y") 400 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"), 401 ABSTFN + "y") 402 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"), 403 ABSTFN + "1") 404 405 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a") 406 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b") 407 408 os.symlink("../" + basename(dirname(ABSTFN)) + "/" + 409 basename(ABSTFN) + "c", ABSTFN+"c") 410 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c") 411 412 # Test using relative path as well. 413 with os_helper.change_cwd(dirname(ABSTFN)): 414 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN) 415 finally: 416 os_helper.unlink(ABSTFN) 417 os_helper.unlink(ABSTFN+"1") 418 os_helper.unlink(ABSTFN+"2") 419 os_helper.unlink(ABSTFN+"y") 420 os_helper.unlink(ABSTFN+"c") 421 os_helper.unlink(ABSTFN+"a") 422 423 @unittest.skipUnless(hasattr(os, "symlink"), 424 "Missing symlink implementation") 425 @skip_if_ABSTFN_contains_backslash 426 def test_realpath_symlink_loops_strict(self): 427 # Bug #43757, raise OSError if we get into an infinite symlink loop in 428 # strict mode. 429 try: 430 os.symlink(ABSTFN, ABSTFN) 431 self.assertRaises(OSError, realpath, ABSTFN, strict=True) 432 433 os.symlink(ABSTFN+"1", ABSTFN+"2") 434 os.symlink(ABSTFN+"2", ABSTFN+"1") 435 self.assertRaises(OSError, realpath, ABSTFN+"1", strict=True) 436 self.assertRaises(OSError, realpath, ABSTFN+"2", strict=True) 437 438 self.assertRaises(OSError, realpath, ABSTFN+"1/x", strict=True) 439 self.assertRaises(OSError, realpath, ABSTFN+"1/..", strict=True) 440 self.assertRaises(OSError, realpath, ABSTFN+"1/../x", strict=True) 441 os.symlink(ABSTFN+"x", ABSTFN+"y") 442 self.assertRaises(OSError, realpath, 443 ABSTFN+"1/../" + basename(ABSTFN) + "y", strict=True) 444 self.assertRaises(OSError, realpath, 445 ABSTFN+"1/../" + basename(ABSTFN) + "1", strict=True) 446 447 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a") 448 self.assertRaises(OSError, realpath, ABSTFN+"a", strict=True) 449 450 os.symlink("../" + basename(dirname(ABSTFN)) + "/" + 451 basename(ABSTFN) + "c", ABSTFN+"c") 452 self.assertRaises(OSError, realpath, ABSTFN+"c", strict=True) 453 454 # Test using relative path as well. 455 with os_helper.change_cwd(dirname(ABSTFN)): 456 self.assertRaises(OSError, realpath, basename(ABSTFN), strict=True) 457 finally: 458 os_helper.unlink(ABSTFN) 459 os_helper.unlink(ABSTFN+"1") 460 os_helper.unlink(ABSTFN+"2") 461 os_helper.unlink(ABSTFN+"y") 462 os_helper.unlink(ABSTFN+"c") 463 os_helper.unlink(ABSTFN+"a") 464 465 @unittest.skipUnless(hasattr(os, "symlink"), 466 "Missing symlink implementation") 467 @skip_if_ABSTFN_contains_backslash 468 def test_realpath_repeated_indirect_symlinks(self): 469 # Issue #6975. 470 try: 471 os.mkdir(ABSTFN) 472 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self') 473 os.symlink('self/self/self', ABSTFN + '/link') 474 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN) 475 finally: 476 os_helper.unlink(ABSTFN + '/self') 477 os_helper.unlink(ABSTFN + '/link') 478 safe_rmdir(ABSTFN) 479 480 @unittest.skipUnless(hasattr(os, "symlink"), 481 "Missing symlink implementation") 482 @skip_if_ABSTFN_contains_backslash 483 def test_realpath_deep_recursion(self): 484 depth = 10 485 try: 486 os.mkdir(ABSTFN) 487 for i in range(depth): 488 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1)) 489 os.symlink('.', ABSTFN + '/0') 490 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN) 491 492 # Test using relative path as well. 493 with os_helper.change_cwd(ABSTFN): 494 self.assertEqual(realpath('%d' % depth), ABSTFN) 495 finally: 496 for i in range(depth + 1): 497 os_helper.unlink(ABSTFN + '/%d' % i) 498 safe_rmdir(ABSTFN) 499 500 @unittest.skipUnless(hasattr(os, "symlink"), 501 "Missing symlink implementation") 502 @skip_if_ABSTFN_contains_backslash 503 def test_realpath_resolve_parents(self): 504 # We also need to resolve any symlinks in the parents of a relative 505 # path passed to realpath. E.g.: current working directory is 506 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call 507 # realpath("a"). This should return /usr/share/doc/a/. 508 try: 509 os.mkdir(ABSTFN) 510 os.mkdir(ABSTFN + "/y") 511 os.symlink(ABSTFN + "/y", ABSTFN + "/k") 512 513 with os_helper.change_cwd(ABSTFN + "/k"): 514 self.assertEqual(realpath("a"), ABSTFN + "/y/a") 515 finally: 516 os_helper.unlink(ABSTFN + "/k") 517 safe_rmdir(ABSTFN + "/y") 518 safe_rmdir(ABSTFN) 519 520 @unittest.skipUnless(hasattr(os, "symlink"), 521 "Missing symlink implementation") 522 @skip_if_ABSTFN_contains_backslash 523 def test_realpath_resolve_before_normalizing(self): 524 # Bug #990669: Symbolic links should be resolved before we 525 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y' 526 # in the following hierarchy: 527 # a/k/y 528 # 529 # and a symbolic link 'link-y' pointing to 'y' in directory 'a', 530 # then realpath("link-y/..") should return 'k', not 'a'. 531 try: 532 os.mkdir(ABSTFN) 533 os.mkdir(ABSTFN + "/k") 534 os.mkdir(ABSTFN + "/k/y") 535 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y") 536 537 # Absolute path. 538 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k") 539 # Relative path. 540 with os_helper.change_cwd(dirname(ABSTFN)): 541 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."), 542 ABSTFN + "/k") 543 finally: 544 os_helper.unlink(ABSTFN + "/link-y") 545 safe_rmdir(ABSTFN + "/k/y") 546 safe_rmdir(ABSTFN + "/k") 547 safe_rmdir(ABSTFN) 548 549 @unittest.skipUnless(hasattr(os, "symlink"), 550 "Missing symlink implementation") 551 @skip_if_ABSTFN_contains_backslash 552 def test_realpath_resolve_first(self): 553 # Bug #1213894: The first component of the path, if not absolute, 554 # must be resolved too. 555 556 try: 557 os.mkdir(ABSTFN) 558 os.mkdir(ABSTFN + "/k") 559 os.symlink(ABSTFN, ABSTFN + "link") 560 with os_helper.change_cwd(dirname(ABSTFN)): 561 base = basename(ABSTFN) 562 self.assertEqual(realpath(base + "link"), ABSTFN) 563 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k") 564 finally: 565 os_helper.unlink(ABSTFN + "link") 566 safe_rmdir(ABSTFN + "/k") 567 safe_rmdir(ABSTFN) 568 569 def test_relpath(self): 570 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar") 571 try: 572 curdir = os.path.split(os.getcwd())[-1] 573 self.assertRaises(ValueError, posixpath.relpath, "") 574 self.assertEqual(posixpath.relpath("a"), "a") 575 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a") 576 self.assertEqual(posixpath.relpath("a/b"), "a/b") 577 self.assertEqual(posixpath.relpath("../a/b"), "../a/b") 578 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a") 579 self.assertEqual(posixpath.relpath("a/b", "../c"), 580 "../"+curdir+"/a/b") 581 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") 582 self.assertEqual(posixpath.relpath("a", "a"), ".") 583 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat') 584 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat') 585 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat') 586 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..') 587 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat') 588 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x') 589 self.assertEqual(posixpath.relpath("/", "/"), '.') 590 self.assertEqual(posixpath.relpath("/a", "/a"), '.') 591 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.') 592 finally: 593 os.getcwd = real_getcwd 594 595 def test_relpath_bytes(self): 596 (real_getcwdb, os.getcwdb) = (os.getcwdb, lambda: br"/home/user/bar") 597 try: 598 curdir = os.path.split(os.getcwdb())[-1] 599 self.assertRaises(ValueError, posixpath.relpath, b"") 600 self.assertEqual(posixpath.relpath(b"a"), b"a") 601 self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a") 602 self.assertEqual(posixpath.relpath(b"a/b"), b"a/b") 603 self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b") 604 self.assertEqual(posixpath.relpath(b"a", b"../b"), 605 b"../"+curdir+b"/a") 606 self.assertEqual(posixpath.relpath(b"a/b", b"../c"), 607 b"../"+curdir+b"/a/b") 608 self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a") 609 self.assertEqual(posixpath.relpath(b"a", b"a"), b".") 610 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat') 611 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat') 612 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat') 613 self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..') 614 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat') 615 self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x') 616 self.assertEqual(posixpath.relpath(b"/", b"/"), b'.') 617 self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.') 618 self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.') 619 620 self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str") 621 self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes") 622 finally: 623 os.getcwdb = real_getcwdb 624 625 def test_commonpath(self): 626 def check(paths, expected): 627 self.assertEqual(posixpath.commonpath(paths), expected) 628 self.assertEqual(posixpath.commonpath([os.fsencode(p) for p in paths]), 629 os.fsencode(expected)) 630 def check_error(exc, paths): 631 self.assertRaises(exc, posixpath.commonpath, paths) 632 self.assertRaises(exc, posixpath.commonpath, 633 [os.fsencode(p) for p in paths]) 634 635 self.assertRaises(ValueError, posixpath.commonpath, []) 636 check_error(ValueError, ['/usr', 'usr']) 637 check_error(ValueError, ['usr', '/usr']) 638 639 check(['/usr/local'], '/usr/local') 640 check(['/usr/local', '/usr/local'], '/usr/local') 641 check(['/usr/local/', '/usr/local'], '/usr/local') 642 check(['/usr/local/', '/usr/local/'], '/usr/local') 643 check(['/usr//local', '//usr/local'], '/usr/local') 644 check(['/usr/./local', '/./usr/local'], '/usr/local') 645 check(['/', '/dev'], '/') 646 check(['/usr', '/dev'], '/') 647 check(['/usr/lib/', '/usr/lib/python3'], '/usr/lib') 648 check(['/usr/lib/', '/usr/lib64/'], '/usr') 649 650 check(['/usr/lib', '/usr/lib64'], '/usr') 651 check(['/usr/lib/', '/usr/lib64'], '/usr') 652 653 check(['spam'], 'spam') 654 check(['spam', 'spam'], 'spam') 655 check(['spam', 'alot'], '') 656 check(['and/jam', 'and/spam'], 'and') 657 check(['and//jam', 'and/spam//'], 'and') 658 check(['and/./jam', './and/spam'], 'and') 659 check(['and/jam', 'and/spam', 'alot'], '') 660 check(['and/jam', 'and/spam', 'and'], 'and') 661 662 check([''], '') 663 check(['', 'spam/alot'], '') 664 check_error(ValueError, ['', '/spam/alot']) 665 666 self.assertRaises(TypeError, posixpath.commonpath, 667 [b'/usr/lib/', '/usr/lib/python3']) 668 self.assertRaises(TypeError, posixpath.commonpath, 669 [b'/usr/lib/', 'usr/lib/python3']) 670 self.assertRaises(TypeError, posixpath.commonpath, 671 [b'usr/lib/', '/usr/lib/python3']) 672 self.assertRaises(TypeError, posixpath.commonpath, 673 ['/usr/lib/', b'/usr/lib/python3']) 674 self.assertRaises(TypeError, posixpath.commonpath, 675 ['/usr/lib/', b'usr/lib/python3']) 676 self.assertRaises(TypeError, posixpath.commonpath, 677 ['usr/lib/', b'/usr/lib/python3']) 678 679 680class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase): 681 pathmodule = posixpath 682 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat'] 683 684 685class PathLikeTests(unittest.TestCase): 686 687 path = posixpath 688 689 def setUp(self): 690 self.file_name = os_helper.TESTFN 691 self.file_path = FakePath(os_helper.TESTFN) 692 self.addCleanup(os_helper.unlink, self.file_name) 693 with open(self.file_name, 'xb', 0) as file: 694 file.write(b"test_posixpath.PathLikeTests") 695 696 def assertPathEqual(self, func): 697 self.assertEqual(func(self.file_path), func(self.file_name)) 698 699 def test_path_normcase(self): 700 self.assertPathEqual(self.path.normcase) 701 702 def test_path_isabs(self): 703 self.assertPathEqual(self.path.isabs) 704 705 def test_path_join(self): 706 self.assertEqual(self.path.join('a', FakePath('b'), 'c'), 707 self.path.join('a', 'b', 'c')) 708 709 def test_path_split(self): 710 self.assertPathEqual(self.path.split) 711 712 def test_path_splitext(self): 713 self.assertPathEqual(self.path.splitext) 714 715 def test_path_splitdrive(self): 716 self.assertPathEqual(self.path.splitdrive) 717 718 def test_path_basename(self): 719 self.assertPathEqual(self.path.basename) 720 721 def test_path_dirname(self): 722 self.assertPathEqual(self.path.dirname) 723 724 def test_path_islink(self): 725 self.assertPathEqual(self.path.islink) 726 727 def test_path_lexists(self): 728 self.assertPathEqual(self.path.lexists) 729 730 def test_path_ismount(self): 731 self.assertPathEqual(self.path.ismount) 732 733 def test_path_expanduser(self): 734 self.assertPathEqual(self.path.expanduser) 735 736 def test_path_expandvars(self): 737 self.assertPathEqual(self.path.expandvars) 738 739 def test_path_normpath(self): 740 self.assertPathEqual(self.path.normpath) 741 742 def test_path_abspath(self): 743 self.assertPathEqual(self.path.abspath) 744 745 def test_path_realpath(self): 746 self.assertPathEqual(self.path.realpath) 747 748 def test_path_relpath(self): 749 self.assertPathEqual(self.path.relpath) 750 751 def test_path_commonpath(self): 752 common_path = self.path.commonpath([self.file_path, self.file_name]) 753 self.assertEqual(common_path, self.file_name) 754 755 756if __name__=="__main__": 757 unittest.main() 758