blob: 8d398ec0103544555d9502c83243cc870ba485e1 [file] [log] [blame]
Brian Curtind40e6f72010-07-08 21:39:08 +00001import os
Victor Stinner1ab6c2d2011-11-15 22:27:41 +01002import posixpath
pxinwrb2304092020-12-16 05:24:00 +08003import sys
Victor Stinner1ab6c2d2011-11-15 22:27:41 +01004import unittest
Georg Brandl89fad142010-03-14 10:23:39 +00005from posixpath import realpath, abspath, dirname, basename
Hai Shi598a9512020-08-07 23:18:38 +08006from test import test_genericpath
7from test.support import import_helper
8from test.support import os_helper
Hai Shid94af3f2020-08-08 17:32:41 +08009from test.support.os_helper import FakePath
Victor Stinnerf2f45552018-12-05 16:49:35 +010010from unittest import mock
Johannes Gijsbers4ec40642004-08-14 15:01:53 +000011
Michael Foord07926f02011-03-16 17:19:16 -040012try:
13 import posix
14except ImportError:
15 posix = None
16
Victor Stinner8f4ef3b2019-07-01 18:28:25 +020017
Johannes Gijsbers4ec40642004-08-14 15:01:53 +000018# 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
Hai Shi598a9512020-08-07 23:18:38 +080021ABSTFN = abspath(os_helper.TESTFN)
Skip Montanaroe809b002000-07-12 00:20:08 +000022
Brian Curtind40e6f72010-07-08 21:39:08 +000023def 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
Guido van Rossumd8faa362007-04-27 19:54:29 +000033def safe_rmdir(dirname):
34 try:
35 os.rmdir(dirname)
36 except OSError:
37 pass
38
Brett Cannonb47243a2003-06-16 21:54:50 +000039class PosixPathTest(unittest.TestCase):
Skip Montanaroe809b002000-07-12 00:20:08 +000040
Guido van Rossumd8faa362007-04-27 19:54:29 +000041 def setUp(self):
42 self.tearDown()
43
44 def tearDown(self):
45 for suffix in ["", "1", "2"]:
Hai Shi598a9512020-08-07 23:18:38 +080046 os_helper.unlink(os_helper.TESTFN + suffix)
47 safe_rmdir(os_helper.TESTFN + suffix)
Guido van Rossumd8faa362007-04-27 19:54:29 +000048
Brett Cannonb47243a2003-06-16 21:54:50 +000049 def test_join(self):
Guido van Rossumf0af3e32008-10-02 18:55:37 +000050 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"),
51 "/bar/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +000052 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
Guido van Rossumf0af3e32008-10-02 18:55:37 +000053 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/")
Skip Montanaroe809b002000-07-12 00:20:08 +000062
Brett Cannonb47243a2003-06-16 21:54:50 +000063 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
Guido van Rossumf0af3e32008-10-02 18:55:37 +000070 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
Guido van Rossumd8faa362007-04-27 19:54:29 +000076 def splitextTest(self, path, filename, ext):
77 self.assertEqual(posixpath.splitext(path), (filename, ext))
78 self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext))
Guido van Rossumf0af3e32008-10-02 18:55:37 +000079 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""))
Brett Cannonb47243a2003-06-16 21:54:50 +0000103
Guido van Rossumd8faa362007-04-27 19:54:29 +0000104 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("", "", "")
Brett Cannonb47243a2003-06-16 21:54:50 +0000117
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
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000125 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
Brett Cannonb47243a2003-06-16 21:54:50 +0000131 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
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000138 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
Brett Cannonb47243a2003-06-16 21:54:50 +0000144 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
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000151 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
Brett Cannonb47243a2003-06-16 21:54:50 +0000157 def test_islink(self):
Hai Shi598a9512020-08-07 23:18:38 +0800158 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
159 self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300160
Hai Shi598a9512020-08-07 23:18:38 +0800161 with open(os_helper.TESTFN + "1", "wb") as f:
Guido van Rossum7dcb8442007-08-27 23:26:56 +0000162 f.write(b"foo")
Hai Shi598a9512020-08-07 23:18:38 +0800163 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300164
Hai Shi598a9512020-08-07 23:18:38 +0800165 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)
Brett Cannonb47243a2003-06-16 21:54:50 +0000172
Hai Shi598a9512020-08-07 23:18:38 +0800173 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)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300177
Brett Cannonb47243a2003-06-16 21:54:50 +0000178 def test_ismount(self):
179 self.assertIs(posixpath.ismount("/"), True)
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300180 self.assertIs(posixpath.ismount(b"/"), True)
Michael Foord07926f02011-03-16 17:19:16 -0400181
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
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300191 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
Hai Shi598a9512020-08-07 23:18:38 +0800196 @unittest.skipUnless(os_helper.can_symlink(),
Michael Foord07926f02011-03-16 17:19:16 -0400197 "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
Brett Cannonb47243a2003-06-16 21:54:50 +0000223
R David Murray750018b2016-08-18 21:27:48 -0400224 @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
Brett Cannonb47243a2003-06-16 21:54:50 +0000246 def test_expanduser(self):
247 self.assertEqual(posixpath.expanduser("foo"), "foo")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000248 self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
Victor Stinnerf2f45552018-12-05 16:49:35 +0100249
250 def test_expanduser_home_envvar(self):
Hai Shi598a9512020-08-07 23:18:38 +0800251 with os_helper.EnvironmentVarGuard() as env:
Victor Stinnerf2f45552018-12-05 16:49:35 +0100252 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
Serhiy Storchakaa3fd0b22016-05-03 21:17:03 +0300259 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")
Brett Cannonb47243a2003-06-16 21:54:50 +0000265
pxinwrb2304092020-12-16 05:24:00 +0800266 @unittest.skipIf(sys.platform == "vxworks",
267 "no home directory on VxWorks")
Victor Stinnerf2f45552018-12-05 16:49:35 +0100268 def test_expanduser_pwd(self):
Hai Shi598a9512020-08-07 23:18:38 +0800269 pwd = import_helper.import_module('pwd')
Victor Stinnerf2f45552018-12-05 16:49:35 +0100270
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
Hai Shi598a9512020-08-07 23:18:38 +0800289 with os_helper.EnvironmentVarGuard() as env:
Victor Stinnerf2f45552018-12-05 16:49:35 +0100290 # 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)
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000306
Brett Cannonb47243a2003-06-16 21:54:50 +0000307 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")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000313 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"),
314 "/foo/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +0000315 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
316
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000317 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
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200327 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200328 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
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200337 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200338 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
Brian Curtin52173d42010-12-02 18:29:18 +0000347 @unittest.skipUnless(hasattr(os, "symlink"),
348 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000349 @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:
Hai Shi598a9512020-08-07 23:18:38 +0800356 os_helper.unlink(ABSTFN)
Tim Petersa45cacf2004-08-20 03:47:14 +0000357
Brian Curtin52173d42010-12-02 18:29:18 +0000358 @unittest.skipUnless(hasattr(os, "symlink"),
359 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000360 @skip_if_ABSTFN_contains_backslash
Barney Galebaecfbd2021-04-28 16:50:17 +0100361 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
Michael Foord07926f02011-03-16 17:19:16 -0400374 def test_realpath_relative(self):
375 try:
376 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
377 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
378 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800379 os_helper.unlink(ABSTFN)
Michael Foord07926f02011-03-16 17:19:16 -0400380
381 @unittest.skipUnless(hasattr(os, "symlink"),
382 "Missing symlink implementation")
383 @skip_if_ABSTFN_contains_backslash
Brian Curtind40e6f72010-07-08 21:39:08 +0000384 def test_realpath_symlink_loops(self):
385 # Bug #930024, return the path unchanged if we get into an infinite
Barney Galebaecfbd2021-04-28 16:50:17 +0100386 # symlink loop in non-strict mode (default).
Brian Curtind40e6f72010-07-08 21:39:08 +0000387 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000388 os.symlink(ABSTFN, ABSTFN)
389 self.assertEqual(realpath(ABSTFN), ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000390
Brian Curtind40e6f72010-07-08 21:39:08 +0000391 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")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000395
Serhiy Storchakadf326912013-02-10 12:22:07 +0200396 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
Brian Curtind40e6f72010-07-08 21:39:08 +0000412 # Test using relative path as well.
Hai Shi598a9512020-08-07 23:18:38 +0800413 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300414 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
Brian Curtind40e6f72010-07-08 21:39:08 +0000415 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800416 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")
Serhiy Storchakadf326912013-02-10 12:22:07 +0200422
423 @unittest.skipUnless(hasattr(os, "symlink"),
424 "Missing symlink implementation")
425 @skip_if_ABSTFN_contains_backslash
Barney Galebaecfbd2021-04-28 16:50:17 +0100426 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
Serhiy Storchakadf326912013-02-10 12:22:07 +0200468 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:
Hai Shi598a9512020-08-07 23:18:38 +0800476 os_helper.unlink(ABSTFN + '/self')
477 os_helper.unlink(ABSTFN + '/link')
Serhiy Storchakadf326912013-02-10 12:22:07 +0200478 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
Serhiy Storchakadf326912013-02-10 12:22:07 +0200485 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.
Hai Shi598a9512020-08-07 23:18:38 +0800493 with os_helper.change_cwd(ABSTFN):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300494 self.assertEqual(realpath('%d' % depth), ABSTFN)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200495 finally:
Serhiy Storchakadf326912013-02-10 12:22:07 +0200496 for i in range(depth + 1):
Hai Shi598a9512020-08-07 23:18:38 +0800497 os_helper.unlink(ABSTFN + '/%d' % i)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200498 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000499
Brian Curtin52173d42010-12-02 18:29:18 +0000500 @unittest.skipUnless(hasattr(os, "symlink"),
501 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000502 @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:
Brian Curtind40e6f72010-07-08 21:39:08 +0000509 os.mkdir(ABSTFN)
510 os.mkdir(ABSTFN + "/y")
511 os.symlink(ABSTFN + "/y", ABSTFN + "/k")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000512
Hai Shi598a9512020-08-07 23:18:38 +0800513 with os_helper.change_cwd(ABSTFN + "/k"):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300514 self.assertEqual(realpath("a"), ABSTFN + "/y/a")
Brian Curtind40e6f72010-07-08 21:39:08 +0000515 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800516 os_helper.unlink(ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000517 safe_rmdir(ABSTFN + "/y")
518 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000519
Brian Curtin52173d42010-12-02 18:29:18 +0000520 @unittest.skipUnless(hasattr(os, "symlink"),
521 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000522 @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:
Brian Curtind40e6f72010-07-08 21:39:08 +0000532 os.mkdir(ABSTFN)
533 os.mkdir(ABSTFN + "/k")
534 os.mkdir(ABSTFN + "/k/y")
535 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000536
Brian Curtind40e6f72010-07-08 21:39:08 +0000537 # Absolute path.
538 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
539 # Relative path.
Hai Shi598a9512020-08-07 23:18:38 +0800540 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300541 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
542 ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000543 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800544 os_helper.unlink(ABSTFN + "/link-y")
Brian Curtind40e6f72010-07-08 21:39:08 +0000545 safe_rmdir(ABSTFN + "/k/y")
546 safe_rmdir(ABSTFN + "/k")
547 safe_rmdir(ABSTFN)
Tim Peters5d36a552005-06-03 22:40:27 +0000548
Brian Curtin52173d42010-12-02 18:29:18 +0000549 @unittest.skipUnless(hasattr(os, "symlink"),
550 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000551 @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.
Georg Brandl268e61c2005-06-03 14:28:50 +0000555
Brian Curtind40e6f72010-07-08 21:39:08 +0000556 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000557 os.mkdir(ABSTFN)
558 os.mkdir(ABSTFN + "/k")
559 os.symlink(ABSTFN, ABSTFN + "link")
Hai Shi598a9512020-08-07 23:18:38 +0800560 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300561 base = basename(ABSTFN)
562 self.assertEqual(realpath(base + "link"), ABSTFN)
563 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000564 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800565 os_helper.unlink(ABSTFN + "link")
Brian Curtind40e6f72010-07-08 21:39:08 +0000566 safe_rmdir(ABSTFN + "/k")
567 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000568
Guido van Rossumd8faa362007-04-27 19:54:29 +0000569 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")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000579 self.assertEqual(posixpath.relpath("a/b", "../c"),
580 "../"+curdir+"/a/b")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000581 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
Christian Heimesfaf2f632008-01-06 16:59:19 +0000582 self.assertEqual(posixpath.relpath("a", "a"), ".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000583 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"), '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000592 finally:
593 os.getcwd = real_getcwd
Brett Cannonb47243a2003-06-16 21:54:50 +0000594
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000595 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".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000610 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'.')
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000619
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
Serhiy Storchaka38220932015-03-31 15:31:53 +0300625 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
Florent Xiclunac9c79782010-03-08 12:24:53 +0000679
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200680class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
Florent Xiclunac9c79782010-03-08 12:24:53 +0000681 pathmodule = posixpath
682 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
683
684
Brett Cannon3f9183b2016-08-26 14:44:48 -0700685class PathLikeTests(unittest.TestCase):
686
687 path = posixpath
688
Brett Cannon3f9183b2016-08-26 14:44:48 -0700689 def setUp(self):
Hai Shi598a9512020-08-07 23:18:38 +0800690 self.file_name = os_helper.TESTFN
691 self.file_path = FakePath(os_helper.TESTFN)
692 self.addCleanup(os_helper.unlink, self.file_name)
Brett Cannon3f9183b2016-08-26 14:44:48 -0700693 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):
Serhiy Storchakab21d1552018-03-02 11:53:51 +0200706 self.assertEqual(self.path.join('a', FakePath('b'), 'c'),
Brett Cannon3f9183b2016-08-26 14:44:48 -0700707 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
Brett Cannonb47243a2003-06-16 21:54:50 +0000756if __name__=="__main__":
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200757 unittest.main()