blob: e18d01f4635a3a8f0b4fb83561ff9464a601e2fe [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
Michael Foord07926f02011-03-16 17:19:16 -0400361 def test_realpath_relative(self):
362 try:
363 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
364 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
365 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800366 os_helper.unlink(ABSTFN)
Michael Foord07926f02011-03-16 17:19:16 -0400367
368 @unittest.skipUnless(hasattr(os, "symlink"),
369 "Missing symlink implementation")
370 @skip_if_ABSTFN_contains_backslash
Brian Curtind40e6f72010-07-08 21:39:08 +0000371 def test_realpath_symlink_loops(self):
372 # Bug #930024, return the path unchanged if we get into an infinite
373 # symlink loop.
374 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000375 os.symlink(ABSTFN, ABSTFN)
376 self.assertEqual(realpath(ABSTFN), ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000377
Brian Curtind40e6f72010-07-08 21:39:08 +0000378 os.symlink(ABSTFN+"1", ABSTFN+"2")
379 os.symlink(ABSTFN+"2", ABSTFN+"1")
380 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
381 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000382
Serhiy Storchakadf326912013-02-10 12:22:07 +0200383 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
384 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
385 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
386 os.symlink(ABSTFN+"x", ABSTFN+"y")
387 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
388 ABSTFN + "y")
389 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
390 ABSTFN + "1")
391
392 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
393 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
394
395 os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
396 basename(ABSTFN) + "c", ABSTFN+"c")
397 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
398
Brian Curtind40e6f72010-07-08 21:39:08 +0000399 # Test using relative path as well.
Hai Shi598a9512020-08-07 23:18:38 +0800400 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300401 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
Brian Curtind40e6f72010-07-08 21:39:08 +0000402 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800403 os_helper.unlink(ABSTFN)
404 os_helper.unlink(ABSTFN+"1")
405 os_helper.unlink(ABSTFN+"2")
406 os_helper.unlink(ABSTFN+"y")
407 os_helper.unlink(ABSTFN+"c")
408 os_helper.unlink(ABSTFN+"a")
Serhiy Storchakadf326912013-02-10 12:22:07 +0200409
410 @unittest.skipUnless(hasattr(os, "symlink"),
411 "Missing symlink implementation")
412 @skip_if_ABSTFN_contains_backslash
413 def test_realpath_repeated_indirect_symlinks(self):
414 # Issue #6975.
415 try:
416 os.mkdir(ABSTFN)
417 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
418 os.symlink('self/self/self', ABSTFN + '/link')
419 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
420 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800421 os_helper.unlink(ABSTFN + '/self')
422 os_helper.unlink(ABSTFN + '/link')
Serhiy Storchakadf326912013-02-10 12:22:07 +0200423 safe_rmdir(ABSTFN)
424
425 @unittest.skipUnless(hasattr(os, "symlink"),
426 "Missing symlink implementation")
427 @skip_if_ABSTFN_contains_backslash
428 def test_realpath_deep_recursion(self):
429 depth = 10
Serhiy Storchakadf326912013-02-10 12:22:07 +0200430 try:
431 os.mkdir(ABSTFN)
432 for i in range(depth):
433 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
434 os.symlink('.', ABSTFN + '/0')
435 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
436
437 # Test using relative path as well.
Hai Shi598a9512020-08-07 23:18:38 +0800438 with os_helper.change_cwd(ABSTFN):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300439 self.assertEqual(realpath('%d' % depth), ABSTFN)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200440 finally:
Serhiy Storchakadf326912013-02-10 12:22:07 +0200441 for i in range(depth + 1):
Hai Shi598a9512020-08-07 23:18:38 +0800442 os_helper.unlink(ABSTFN + '/%d' % i)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200443 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000444
Brian Curtin52173d42010-12-02 18:29:18 +0000445 @unittest.skipUnless(hasattr(os, "symlink"),
446 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000447 @skip_if_ABSTFN_contains_backslash
448 def test_realpath_resolve_parents(self):
449 # We also need to resolve any symlinks in the parents of a relative
450 # path passed to realpath. E.g.: current working directory is
451 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
452 # realpath("a"). This should return /usr/share/doc/a/.
453 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000454 os.mkdir(ABSTFN)
455 os.mkdir(ABSTFN + "/y")
456 os.symlink(ABSTFN + "/y", ABSTFN + "/k")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000457
Hai Shi598a9512020-08-07 23:18:38 +0800458 with os_helper.change_cwd(ABSTFN + "/k"):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300459 self.assertEqual(realpath("a"), ABSTFN + "/y/a")
Brian Curtind40e6f72010-07-08 21:39:08 +0000460 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800461 os_helper.unlink(ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000462 safe_rmdir(ABSTFN + "/y")
463 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000464
Brian Curtin52173d42010-12-02 18:29:18 +0000465 @unittest.skipUnless(hasattr(os, "symlink"),
466 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000467 @skip_if_ABSTFN_contains_backslash
468 def test_realpath_resolve_before_normalizing(self):
469 # Bug #990669: Symbolic links should be resolved before we
470 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
471 # in the following hierarchy:
472 # a/k/y
473 #
474 # and a symbolic link 'link-y' pointing to 'y' in directory 'a',
475 # then realpath("link-y/..") should return 'k', not 'a'.
476 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000477 os.mkdir(ABSTFN)
478 os.mkdir(ABSTFN + "/k")
479 os.mkdir(ABSTFN + "/k/y")
480 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000481
Brian Curtind40e6f72010-07-08 21:39:08 +0000482 # Absolute path.
483 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
484 # Relative path.
Hai Shi598a9512020-08-07 23:18:38 +0800485 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300486 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
487 ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000488 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800489 os_helper.unlink(ABSTFN + "/link-y")
Brian Curtind40e6f72010-07-08 21:39:08 +0000490 safe_rmdir(ABSTFN + "/k/y")
491 safe_rmdir(ABSTFN + "/k")
492 safe_rmdir(ABSTFN)
Tim Peters5d36a552005-06-03 22:40:27 +0000493
Brian Curtin52173d42010-12-02 18:29:18 +0000494 @unittest.skipUnless(hasattr(os, "symlink"),
495 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000496 @skip_if_ABSTFN_contains_backslash
497 def test_realpath_resolve_first(self):
498 # Bug #1213894: The first component of the path, if not absolute,
499 # must be resolved too.
Georg Brandl268e61c2005-06-03 14:28:50 +0000500
Brian Curtind40e6f72010-07-08 21:39:08 +0000501 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000502 os.mkdir(ABSTFN)
503 os.mkdir(ABSTFN + "/k")
504 os.symlink(ABSTFN, ABSTFN + "link")
Hai Shi598a9512020-08-07 23:18:38 +0800505 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300506 base = basename(ABSTFN)
507 self.assertEqual(realpath(base + "link"), ABSTFN)
508 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000509 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800510 os_helper.unlink(ABSTFN + "link")
Brian Curtind40e6f72010-07-08 21:39:08 +0000511 safe_rmdir(ABSTFN + "/k")
512 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000513
Guido van Rossumd8faa362007-04-27 19:54:29 +0000514 def test_relpath(self):
515 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
516 try:
517 curdir = os.path.split(os.getcwd())[-1]
518 self.assertRaises(ValueError, posixpath.relpath, "")
519 self.assertEqual(posixpath.relpath("a"), "a")
520 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
521 self.assertEqual(posixpath.relpath("a/b"), "a/b")
522 self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
523 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000524 self.assertEqual(posixpath.relpath("a/b", "../c"),
525 "../"+curdir+"/a/b")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000526 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
Christian Heimesfaf2f632008-01-06 16:59:19 +0000527 self.assertEqual(posixpath.relpath("a", "a"), ".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000528 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat')
529 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat')
530 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat')
531 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..')
532 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat')
533 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x')
534 self.assertEqual(posixpath.relpath("/", "/"), '.')
535 self.assertEqual(posixpath.relpath("/a", "/a"), '.')
536 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000537 finally:
538 os.getcwd = real_getcwd
Brett Cannonb47243a2003-06-16 21:54:50 +0000539
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000540 def test_relpath_bytes(self):
541 (real_getcwdb, os.getcwdb) = (os.getcwdb, lambda: br"/home/user/bar")
542 try:
543 curdir = os.path.split(os.getcwdb())[-1]
544 self.assertRaises(ValueError, posixpath.relpath, b"")
545 self.assertEqual(posixpath.relpath(b"a"), b"a")
546 self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a")
547 self.assertEqual(posixpath.relpath(b"a/b"), b"a/b")
548 self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b")
549 self.assertEqual(posixpath.relpath(b"a", b"../b"),
550 b"../"+curdir+b"/a")
551 self.assertEqual(posixpath.relpath(b"a/b", b"../c"),
552 b"../"+curdir+b"/a/b")
553 self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a")
554 self.assertEqual(posixpath.relpath(b"a", b"a"), b".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000555 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat')
556 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat')
557 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat')
558 self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..')
559 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat')
560 self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x')
561 self.assertEqual(posixpath.relpath(b"/", b"/"), b'.')
562 self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.')
563 self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.')
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000564
565 self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str")
566 self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes")
567 finally:
568 os.getcwdb = real_getcwdb
569
Serhiy Storchaka38220932015-03-31 15:31:53 +0300570 def test_commonpath(self):
571 def check(paths, expected):
572 self.assertEqual(posixpath.commonpath(paths), expected)
573 self.assertEqual(posixpath.commonpath([os.fsencode(p) for p in paths]),
574 os.fsencode(expected))
575 def check_error(exc, paths):
576 self.assertRaises(exc, posixpath.commonpath, paths)
577 self.assertRaises(exc, posixpath.commonpath,
578 [os.fsencode(p) for p in paths])
579
580 self.assertRaises(ValueError, posixpath.commonpath, [])
581 check_error(ValueError, ['/usr', 'usr'])
582 check_error(ValueError, ['usr', '/usr'])
583
584 check(['/usr/local'], '/usr/local')
585 check(['/usr/local', '/usr/local'], '/usr/local')
586 check(['/usr/local/', '/usr/local'], '/usr/local')
587 check(['/usr/local/', '/usr/local/'], '/usr/local')
588 check(['/usr//local', '//usr/local'], '/usr/local')
589 check(['/usr/./local', '/./usr/local'], '/usr/local')
590 check(['/', '/dev'], '/')
591 check(['/usr', '/dev'], '/')
592 check(['/usr/lib/', '/usr/lib/python3'], '/usr/lib')
593 check(['/usr/lib/', '/usr/lib64/'], '/usr')
594
595 check(['/usr/lib', '/usr/lib64'], '/usr')
596 check(['/usr/lib/', '/usr/lib64'], '/usr')
597
598 check(['spam'], 'spam')
599 check(['spam', 'spam'], 'spam')
600 check(['spam', 'alot'], '')
601 check(['and/jam', 'and/spam'], 'and')
602 check(['and//jam', 'and/spam//'], 'and')
603 check(['and/./jam', './and/spam'], 'and')
604 check(['and/jam', 'and/spam', 'alot'], '')
605 check(['and/jam', 'and/spam', 'and'], 'and')
606
607 check([''], '')
608 check(['', 'spam/alot'], '')
609 check_error(ValueError, ['', '/spam/alot'])
610
611 self.assertRaises(TypeError, posixpath.commonpath,
612 [b'/usr/lib/', '/usr/lib/python3'])
613 self.assertRaises(TypeError, posixpath.commonpath,
614 [b'/usr/lib/', 'usr/lib/python3'])
615 self.assertRaises(TypeError, posixpath.commonpath,
616 [b'usr/lib/', '/usr/lib/python3'])
617 self.assertRaises(TypeError, posixpath.commonpath,
618 ['/usr/lib/', b'/usr/lib/python3'])
619 self.assertRaises(TypeError, posixpath.commonpath,
620 ['/usr/lib/', b'usr/lib/python3'])
621 self.assertRaises(TypeError, posixpath.commonpath,
622 ['usr/lib/', b'/usr/lib/python3'])
623
Florent Xiclunac9c79782010-03-08 12:24:53 +0000624
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200625class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
Florent Xiclunac9c79782010-03-08 12:24:53 +0000626 pathmodule = posixpath
627 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
628
629
Brett Cannon3f9183b2016-08-26 14:44:48 -0700630class PathLikeTests(unittest.TestCase):
631
632 path = posixpath
633
Brett Cannon3f9183b2016-08-26 14:44:48 -0700634 def setUp(self):
Hai Shi598a9512020-08-07 23:18:38 +0800635 self.file_name = os_helper.TESTFN
636 self.file_path = FakePath(os_helper.TESTFN)
637 self.addCleanup(os_helper.unlink, self.file_name)
Brett Cannon3f9183b2016-08-26 14:44:48 -0700638 with open(self.file_name, 'xb', 0) as file:
639 file.write(b"test_posixpath.PathLikeTests")
640
641 def assertPathEqual(self, func):
642 self.assertEqual(func(self.file_path), func(self.file_name))
643
644 def test_path_normcase(self):
645 self.assertPathEqual(self.path.normcase)
646
647 def test_path_isabs(self):
648 self.assertPathEqual(self.path.isabs)
649
650 def test_path_join(self):
Serhiy Storchakab21d1552018-03-02 11:53:51 +0200651 self.assertEqual(self.path.join('a', FakePath('b'), 'c'),
Brett Cannon3f9183b2016-08-26 14:44:48 -0700652 self.path.join('a', 'b', 'c'))
653
654 def test_path_split(self):
655 self.assertPathEqual(self.path.split)
656
657 def test_path_splitext(self):
658 self.assertPathEqual(self.path.splitext)
659
660 def test_path_splitdrive(self):
661 self.assertPathEqual(self.path.splitdrive)
662
663 def test_path_basename(self):
664 self.assertPathEqual(self.path.basename)
665
666 def test_path_dirname(self):
667 self.assertPathEqual(self.path.dirname)
668
669 def test_path_islink(self):
670 self.assertPathEqual(self.path.islink)
671
672 def test_path_lexists(self):
673 self.assertPathEqual(self.path.lexists)
674
675 def test_path_ismount(self):
676 self.assertPathEqual(self.path.ismount)
677
678 def test_path_expanduser(self):
679 self.assertPathEqual(self.path.expanduser)
680
681 def test_path_expandvars(self):
682 self.assertPathEqual(self.path.expandvars)
683
684 def test_path_normpath(self):
685 self.assertPathEqual(self.path.normpath)
686
687 def test_path_abspath(self):
688 self.assertPathEqual(self.path.abspath)
689
690 def test_path_realpath(self):
691 self.assertPathEqual(self.path.realpath)
692
693 def test_path_relpath(self):
694 self.assertPathEqual(self.path.relpath)
695
696 def test_path_commonpath(self):
697 common_path = self.path.commonpath([self.file_path, self.file_name])
698 self.assertEqual(common_path, self.file_name)
699
700
Brett Cannonb47243a2003-06-16 21:54:50 +0000701if __name__=="__main__":
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200702 unittest.main()