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