blob: 42fd8ef8b17465a7081e17371820a30f7a6a54fa [file] [log] [blame]
Brian Curtind40e6f72010-07-08 21:39:08 +00001import os
Victor Stinner1ab6c2d2011-11-15 22:27:41 +01002import posixpath
Victor Stinner1ab6c2d2011-11-15 22:27:41 +01003import unittest
Georg Brandl89fad142010-03-14 10:23:39 +00004from posixpath import realpath, abspath, dirname, basename
Hai Shi598a9512020-08-07 23:18:38 +08005from test import test_genericpath
6from test.support import import_helper
7from test.support import os_helper
Hai Shid94af3f2020-08-08 17:32:41 +08008from test.support.os_helper import FakePath
Victor Stinnerf2f45552018-12-05 16:49:35 +01009from unittest import mock
Johannes Gijsbers4ec40642004-08-14 15:01:53 +000010
Michael Foord07926f02011-03-16 17:19:16 -040011try:
12 import posix
13except ImportError:
14 posix = None
15
Victor Stinner8f4ef3b2019-07-01 18:28:25 +020016
Johannes Gijsbers4ec40642004-08-14 15:01:53 +000017# An absolute path to a temporary filename for testing. We can't rely on TESTFN
18# being an absolute path, so we need this.
19
Hai Shi598a9512020-08-07 23:18:38 +080020ABSTFN = abspath(os_helper.TESTFN)
Skip Montanaroe809b002000-07-12 00:20:08 +000021
Brian Curtind40e6f72010-07-08 21:39:08 +000022def skip_if_ABSTFN_contains_backslash(test):
23 """
24 On Windows, posixpath.abspath still returns paths with backslashes
25 instead of posix forward slashes. If this is the case, several tests
26 fail, so skip them.
27 """
28 found_backslash = '\\' in ABSTFN
29 msg = "ABSTFN is not a posix path - tests fail"
30 return [test, unittest.skip(msg)(test)][found_backslash]
31
Guido van Rossumd8faa362007-04-27 19:54:29 +000032def safe_rmdir(dirname):
33 try:
34 os.rmdir(dirname)
35 except OSError:
36 pass
37
Brett Cannonb47243a2003-06-16 21:54:50 +000038class PosixPathTest(unittest.TestCase):
Skip Montanaroe809b002000-07-12 00:20:08 +000039
Guido van Rossumd8faa362007-04-27 19:54:29 +000040 def setUp(self):
41 self.tearDown()
42
43 def tearDown(self):
44 for suffix in ["", "1", "2"]:
Hai Shi598a9512020-08-07 23:18:38 +080045 os_helper.unlink(os_helper.TESTFN + suffix)
46 safe_rmdir(os_helper.TESTFN + suffix)
Guido van Rossumd8faa362007-04-27 19:54:29 +000047
Brett Cannonb47243a2003-06-16 21:54:50 +000048 def test_join(self):
Guido van Rossumf0af3e32008-10-02 18:55:37 +000049 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"),
50 "/bar/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +000051 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
Guido van Rossumf0af3e32008-10-02 18:55:37 +000052 self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"),
53 "/foo/bar/baz/")
54
55 self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"),
56 b"/bar/baz")
57 self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"),
58 b"/foo/bar/baz")
59 self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"),
60 b"/foo/bar/baz/")
Skip Montanaroe809b002000-07-12 00:20:08 +000061
Brett Cannonb47243a2003-06-16 21:54:50 +000062 def test_split(self):
63 self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
64 self.assertEqual(posixpath.split("/"), ("/", ""))
65 self.assertEqual(posixpath.split("foo"), ("", "foo"))
66 self.assertEqual(posixpath.split("////foo"), ("////", "foo"))
67 self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar"))
68
Guido van Rossumf0af3e32008-10-02 18:55:37 +000069 self.assertEqual(posixpath.split(b"/foo/bar"), (b"/foo", b"bar"))
70 self.assertEqual(posixpath.split(b"/"), (b"/", b""))
71 self.assertEqual(posixpath.split(b"foo"), (b"", b"foo"))
72 self.assertEqual(posixpath.split(b"////foo"), (b"////", b"foo"))
73 self.assertEqual(posixpath.split(b"//foo//bar"), (b"//foo", b"bar"))
74
Guido van Rossumd8faa362007-04-27 19:54:29 +000075 def splitextTest(self, path, filename, ext):
76 self.assertEqual(posixpath.splitext(path), (filename, ext))
77 self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext))
Guido van Rossumf0af3e32008-10-02 18:55:37 +000078 self.assertEqual(posixpath.splitext("abc/" + path),
79 ("abc/" + filename, ext))
80 self.assertEqual(posixpath.splitext("abc.def/" + path),
81 ("abc.def/" + filename, ext))
82 self.assertEqual(posixpath.splitext("/abc.def/" + path),
83 ("/abc.def/" + filename, ext))
84 self.assertEqual(posixpath.splitext(path + "/"),
85 (filename + ext + "/", ""))
86
87 path = bytes(path, "ASCII")
88 filename = bytes(filename, "ASCII")
89 ext = bytes(ext, "ASCII")
90
91 self.assertEqual(posixpath.splitext(path), (filename, ext))
92 self.assertEqual(posixpath.splitext(b"/" + path),
93 (b"/" + filename, ext))
94 self.assertEqual(posixpath.splitext(b"abc/" + path),
95 (b"abc/" + filename, ext))
96 self.assertEqual(posixpath.splitext(b"abc.def/" + path),
97 (b"abc.def/" + filename, ext))
98 self.assertEqual(posixpath.splitext(b"/abc.def/" + path),
99 (b"/abc.def/" + filename, ext))
100 self.assertEqual(posixpath.splitext(path + b"/"),
101 (filename + ext + b"/", b""))
Brett Cannonb47243a2003-06-16 21:54:50 +0000102
Guido van Rossumd8faa362007-04-27 19:54:29 +0000103 def test_splitext(self):
104 self.splitextTest("foo.bar", "foo", ".bar")
105 self.splitextTest("foo.boo.bar", "foo.boo", ".bar")
106 self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar")
107 self.splitextTest(".csh.rc", ".csh", ".rc")
108 self.splitextTest("nodots", "nodots", "")
109 self.splitextTest(".cshrc", ".cshrc", "")
110 self.splitextTest("...manydots", "...manydots", "")
111 self.splitextTest("...manydots.ext", "...manydots", ".ext")
112 self.splitextTest(".", ".", "")
113 self.splitextTest("..", "..", "")
114 self.splitextTest("........", "........", "")
115 self.splitextTest("", "", "")
Brett Cannonb47243a2003-06-16 21:54:50 +0000116
117 def test_isabs(self):
118 self.assertIs(posixpath.isabs(""), False)
119 self.assertIs(posixpath.isabs("/"), True)
120 self.assertIs(posixpath.isabs("/foo"), True)
121 self.assertIs(posixpath.isabs("/foo/bar"), True)
122 self.assertIs(posixpath.isabs("foo/bar"), False)
123
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000124 self.assertIs(posixpath.isabs(b""), False)
125 self.assertIs(posixpath.isabs(b"/"), True)
126 self.assertIs(posixpath.isabs(b"/foo"), True)
127 self.assertIs(posixpath.isabs(b"/foo/bar"), True)
128 self.assertIs(posixpath.isabs(b"foo/bar"), False)
129
Brett Cannonb47243a2003-06-16 21:54:50 +0000130 def test_basename(self):
131 self.assertEqual(posixpath.basename("/foo/bar"), "bar")
132 self.assertEqual(posixpath.basename("/"), "")
133 self.assertEqual(posixpath.basename("foo"), "foo")
134 self.assertEqual(posixpath.basename("////foo"), "foo")
135 self.assertEqual(posixpath.basename("//foo//bar"), "bar")
136
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000137 self.assertEqual(posixpath.basename(b"/foo/bar"), b"bar")
138 self.assertEqual(posixpath.basename(b"/"), b"")
139 self.assertEqual(posixpath.basename(b"foo"), b"foo")
140 self.assertEqual(posixpath.basename(b"////foo"), b"foo")
141 self.assertEqual(posixpath.basename(b"//foo//bar"), b"bar")
142
Brett Cannonb47243a2003-06-16 21:54:50 +0000143 def test_dirname(self):
144 self.assertEqual(posixpath.dirname("/foo/bar"), "/foo")
145 self.assertEqual(posixpath.dirname("/"), "/")
146 self.assertEqual(posixpath.dirname("foo"), "")
147 self.assertEqual(posixpath.dirname("////foo"), "////")
148 self.assertEqual(posixpath.dirname("//foo//bar"), "//foo")
149
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000150 self.assertEqual(posixpath.dirname(b"/foo/bar"), b"/foo")
151 self.assertEqual(posixpath.dirname(b"/"), b"/")
152 self.assertEqual(posixpath.dirname(b"foo"), b"")
153 self.assertEqual(posixpath.dirname(b"////foo"), b"////")
154 self.assertEqual(posixpath.dirname(b"//foo//bar"), b"//foo")
155
Brett Cannonb47243a2003-06-16 21:54:50 +0000156 def test_islink(self):
Hai Shi598a9512020-08-07 23:18:38 +0800157 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
158 self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300159
Hai Shi598a9512020-08-07 23:18:38 +0800160 with open(os_helper.TESTFN + "1", "wb") as f:
Guido van Rossum7dcb8442007-08-27 23:26:56 +0000161 f.write(b"foo")
Hai Shi598a9512020-08-07 23:18:38 +0800162 self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300163
Hai Shi598a9512020-08-07 23:18:38 +0800164 if os_helper.can_symlink():
165 os.symlink(os_helper.TESTFN + "1", os_helper.TESTFN + "2")
166 self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True)
167 os.remove(os_helper.TESTFN + "1")
168 self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True)
169 self.assertIs(posixpath.exists(os_helper.TESTFN + "2"), False)
170 self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), True)
Brett Cannonb47243a2003-06-16 21:54:50 +0000171
Hai Shi598a9512020-08-07 23:18:38 +0800172 self.assertIs(posixpath.islink(os_helper.TESTFN + "\udfff"), False)
173 self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\xff"), False)
174 self.assertIs(posixpath.islink(os_helper.TESTFN + "\x00"), False)
175 self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\x00"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300176
Brett Cannonb47243a2003-06-16 21:54:50 +0000177 def test_ismount(self):
178 self.assertIs(posixpath.ismount("/"), True)
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300179 self.assertIs(posixpath.ismount(b"/"), True)
Michael Foord07926f02011-03-16 17:19:16 -0400180
181 def test_ismount_non_existent(self):
182 # Non-existent mountpoint.
183 self.assertIs(posixpath.ismount(ABSTFN), False)
184 try:
185 os.mkdir(ABSTFN)
186 self.assertIs(posixpath.ismount(ABSTFN), False)
187 finally:
188 safe_rmdir(ABSTFN)
189
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300190 self.assertIs(posixpath.ismount('/\udfff'), False)
191 self.assertIs(posixpath.ismount(b'/\xff'), False)
192 self.assertIs(posixpath.ismount('/\x00'), False)
193 self.assertIs(posixpath.ismount(b'/\x00'), False)
194
Hai Shi598a9512020-08-07 23:18:38 +0800195 @unittest.skipUnless(os_helper.can_symlink(),
Michael Foord07926f02011-03-16 17:19:16 -0400196 "Test requires symlink support")
197 def test_ismount_symlinks(self):
198 # Symlinks are never mountpoints.
199 try:
200 os.symlink("/", ABSTFN)
201 self.assertIs(posixpath.ismount(ABSTFN), False)
202 finally:
203 os.unlink(ABSTFN)
204
205 @unittest.skipIf(posix is None, "Test requires posix module")
206 def test_ismount_different_device(self):
207 # Simulate the path being on a different device from its parent by
208 # mocking out st_dev.
209 save_lstat = os.lstat
210 def fake_lstat(path):
211 st_ino = 0
212 st_dev = 0
213 if path == ABSTFN:
214 st_dev = 1
215 st_ino = 1
216 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
217 try:
218 os.lstat = fake_lstat
219 self.assertIs(posixpath.ismount(ABSTFN), True)
220 finally:
221 os.lstat = save_lstat
Brett Cannonb47243a2003-06-16 21:54:50 +0000222
R David Murray750018b2016-08-18 21:27:48 -0400223 @unittest.skipIf(posix is None, "Test requires posix module")
224 def test_ismount_directory_not_readable(self):
225 # issue #2466: Simulate ismount run on a directory that is not
226 # readable, which used to return False.
227 save_lstat = os.lstat
228 def fake_lstat(path):
229 st_ino = 0
230 st_dev = 0
231 if path.startswith(ABSTFN) and path != ABSTFN:
232 # ismount tries to read something inside the ABSTFN directory;
233 # simulate this being forbidden (no read permission).
234 raise OSError("Fake [Errno 13] Permission denied")
235 if path == ABSTFN:
236 st_dev = 1
237 st_ino = 1
238 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
239 try:
240 os.lstat = fake_lstat
241 self.assertIs(posixpath.ismount(ABSTFN), True)
242 finally:
243 os.lstat = save_lstat
244
Brett Cannonb47243a2003-06-16 21:54:50 +0000245 def test_expanduser(self):
246 self.assertEqual(posixpath.expanduser("foo"), "foo")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000247 self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
Victor Stinnerf2f45552018-12-05 16:49:35 +0100248
249 def test_expanduser_home_envvar(self):
Hai Shi598a9512020-08-07 23:18:38 +0800250 with os_helper.EnvironmentVarGuard() as env:
Victor Stinnerf2f45552018-12-05 16:49:35 +0100251 env['HOME'] = '/home/victor'
252 self.assertEqual(posixpath.expanduser("~"), "/home/victor")
253
254 # expanduser() strips trailing slash
255 env['HOME'] = '/home/victor/'
256 self.assertEqual(posixpath.expanduser("~"), "/home/victor")
257
Serhiy Storchakaa3fd0b22016-05-03 21:17:03 +0300258 for home in '/', '', '//', '///':
259 with self.subTest(home=home):
260 env['HOME'] = home
261 self.assertEqual(posixpath.expanduser("~"), "/")
262 self.assertEqual(posixpath.expanduser("~/"), "/")
263 self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
Brett Cannonb47243a2003-06-16 21:54:50 +0000264
Victor Stinnerf2f45552018-12-05 16:49:35 +0100265 def test_expanduser_pwd(self):
Hai Shi598a9512020-08-07 23:18:38 +0800266 pwd = import_helper.import_module('pwd')
Victor Stinnerf2f45552018-12-05 16:49:35 +0100267
268 self.assertIsInstance(posixpath.expanduser("~/"), str)
269 self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
270
271 # if home directory == root directory, this test makes no sense
272 if posixpath.expanduser("~") != '/':
273 self.assertEqual(
274 posixpath.expanduser("~") + "/",
275 posixpath.expanduser("~/")
276 )
277 self.assertEqual(
278 posixpath.expanduser(b"~") + b"/",
279 posixpath.expanduser(b"~/")
280 )
281 self.assertIsInstance(posixpath.expanduser("~root/"), str)
282 self.assertIsInstance(posixpath.expanduser("~foo/"), str)
283 self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
284 self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
285
Hai Shi598a9512020-08-07 23:18:38 +0800286 with os_helper.EnvironmentVarGuard() as env:
Victor Stinnerf2f45552018-12-05 16:49:35 +0100287 # expanduser should fall back to using the password database
288 del env['HOME']
289
290 home = pwd.getpwuid(os.getuid()).pw_dir
291 # $HOME can end with a trailing /, so strip it (see #17809)
292 home = home.rstrip("/") or '/'
293 self.assertEqual(posixpath.expanduser("~"), home)
294
295 # bpo-10496: If the HOME environment variable is not set and the
296 # user (current identifier or name in the path) doesn't exist in
297 # the password database (pwd.getuid() or pwd.getpwnam() fail),
298 # expanduser() must return the path unchanged.
299 with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError), \
300 mock.patch.object(pwd, 'getpwnam', side_effect=KeyError):
301 for path in ('~', '~/.local', '~vstinner/'):
302 self.assertEqual(posixpath.expanduser(path), path)
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000303
Brett Cannonb47243a2003-06-16 21:54:50 +0000304 def test_normpath(self):
305 self.assertEqual(posixpath.normpath(""), ".")
306 self.assertEqual(posixpath.normpath("/"), "/")
307 self.assertEqual(posixpath.normpath("//"), "//")
308 self.assertEqual(posixpath.normpath("///"), "/")
309 self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000310 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"),
311 "/foo/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +0000312 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
313
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000314 self.assertEqual(posixpath.normpath(b""), b".")
315 self.assertEqual(posixpath.normpath(b"/"), b"/")
316 self.assertEqual(posixpath.normpath(b"//"), b"//")
317 self.assertEqual(posixpath.normpath(b"///"), b"/")
318 self.assertEqual(posixpath.normpath(b"///foo/.//bar//"), b"/foo/bar")
319 self.assertEqual(posixpath.normpath(b"///foo/.//bar//.//..//.//baz"),
320 b"/foo/baz")
321 self.assertEqual(posixpath.normpath(b"///..//./foo/.//bar"),
322 b"/foo/bar")
323
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200324 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200325 def test_realpath_curdir(self):
326 self.assertEqual(realpath('.'), os.getcwd())
327 self.assertEqual(realpath('./.'), os.getcwd())
328 self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
329
330 self.assertEqual(realpath(b'.'), os.getcwdb())
331 self.assertEqual(realpath(b'./.'), os.getcwdb())
332 self.assertEqual(realpath(b'/'.join([b'.'] * 100)), os.getcwdb())
333
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200334 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200335 def test_realpath_pardir(self):
336 self.assertEqual(realpath('..'), dirname(os.getcwd()))
337 self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
338 self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
339
340 self.assertEqual(realpath(b'..'), dirname(os.getcwdb()))
341 self.assertEqual(realpath(b'../..'), dirname(dirname(os.getcwdb())))
342 self.assertEqual(realpath(b'/'.join([b'..'] * 100)), b'/')
343
Brian Curtin52173d42010-12-02 18:29:18 +0000344 @unittest.skipUnless(hasattr(os, "symlink"),
345 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000346 @skip_if_ABSTFN_contains_backslash
347 def test_realpath_basic(self):
348 # Basic operation.
349 try:
350 os.symlink(ABSTFN+"1", ABSTFN)
351 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
352 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800353 os_helper.unlink(ABSTFN)
Tim Petersa45cacf2004-08-20 03:47:14 +0000354
Brian Curtin52173d42010-12-02 18:29:18 +0000355 @unittest.skipUnless(hasattr(os, "symlink"),
356 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000357 @skip_if_ABSTFN_contains_backslash
Michael Foord07926f02011-03-16 17:19:16 -0400358 def test_realpath_relative(self):
359 try:
360 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
361 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
362 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800363 os_helper.unlink(ABSTFN)
Michael Foord07926f02011-03-16 17:19:16 -0400364
365 @unittest.skipUnless(hasattr(os, "symlink"),
366 "Missing symlink implementation")
367 @skip_if_ABSTFN_contains_backslash
Brian Curtind40e6f72010-07-08 21:39:08 +0000368 def test_realpath_symlink_loops(self):
369 # Bug #930024, return the path unchanged if we get into an infinite
370 # symlink loop.
371 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000372 os.symlink(ABSTFN, ABSTFN)
373 self.assertEqual(realpath(ABSTFN), ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000374
Brian Curtind40e6f72010-07-08 21:39:08 +0000375 os.symlink(ABSTFN+"1", ABSTFN+"2")
376 os.symlink(ABSTFN+"2", ABSTFN+"1")
377 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
378 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000379
Serhiy Storchakadf326912013-02-10 12:22:07 +0200380 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
381 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
382 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
383 os.symlink(ABSTFN+"x", ABSTFN+"y")
384 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
385 ABSTFN + "y")
386 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
387 ABSTFN + "1")
388
389 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
390 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
391
392 os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
393 basename(ABSTFN) + "c", ABSTFN+"c")
394 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
395
Brian Curtind40e6f72010-07-08 21:39:08 +0000396 # Test using relative path as well.
Hai Shi598a9512020-08-07 23:18:38 +0800397 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300398 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
Brian Curtind40e6f72010-07-08 21:39:08 +0000399 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800400 os_helper.unlink(ABSTFN)
401 os_helper.unlink(ABSTFN+"1")
402 os_helper.unlink(ABSTFN+"2")
403 os_helper.unlink(ABSTFN+"y")
404 os_helper.unlink(ABSTFN+"c")
405 os_helper.unlink(ABSTFN+"a")
Serhiy Storchakadf326912013-02-10 12:22:07 +0200406
407 @unittest.skipUnless(hasattr(os, "symlink"),
408 "Missing symlink implementation")
409 @skip_if_ABSTFN_contains_backslash
410 def test_realpath_repeated_indirect_symlinks(self):
411 # Issue #6975.
412 try:
413 os.mkdir(ABSTFN)
414 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
415 os.symlink('self/self/self', ABSTFN + '/link')
416 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
417 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800418 os_helper.unlink(ABSTFN + '/self')
419 os_helper.unlink(ABSTFN + '/link')
Serhiy Storchakadf326912013-02-10 12:22:07 +0200420 safe_rmdir(ABSTFN)
421
422 @unittest.skipUnless(hasattr(os, "symlink"),
423 "Missing symlink implementation")
424 @skip_if_ABSTFN_contains_backslash
425 def test_realpath_deep_recursion(self):
426 depth = 10
Serhiy Storchakadf326912013-02-10 12:22:07 +0200427 try:
428 os.mkdir(ABSTFN)
429 for i in range(depth):
430 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
431 os.symlink('.', ABSTFN + '/0')
432 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
433
434 # Test using relative path as well.
Hai Shi598a9512020-08-07 23:18:38 +0800435 with os_helper.change_cwd(ABSTFN):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300436 self.assertEqual(realpath('%d' % depth), ABSTFN)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200437 finally:
Serhiy Storchakadf326912013-02-10 12:22:07 +0200438 for i in range(depth + 1):
Hai Shi598a9512020-08-07 23:18:38 +0800439 os_helper.unlink(ABSTFN + '/%d' % i)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200440 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000441
Brian Curtin52173d42010-12-02 18:29:18 +0000442 @unittest.skipUnless(hasattr(os, "symlink"),
443 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000444 @skip_if_ABSTFN_contains_backslash
445 def test_realpath_resolve_parents(self):
446 # We also need to resolve any symlinks in the parents of a relative
447 # path passed to realpath. E.g.: current working directory is
448 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
449 # realpath("a"). This should return /usr/share/doc/a/.
450 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000451 os.mkdir(ABSTFN)
452 os.mkdir(ABSTFN + "/y")
453 os.symlink(ABSTFN + "/y", ABSTFN + "/k")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000454
Hai Shi598a9512020-08-07 23:18:38 +0800455 with os_helper.change_cwd(ABSTFN + "/k"):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300456 self.assertEqual(realpath("a"), ABSTFN + "/y/a")
Brian Curtind40e6f72010-07-08 21:39:08 +0000457 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800458 os_helper.unlink(ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000459 safe_rmdir(ABSTFN + "/y")
460 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000461
Brian Curtin52173d42010-12-02 18:29:18 +0000462 @unittest.skipUnless(hasattr(os, "symlink"),
463 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000464 @skip_if_ABSTFN_contains_backslash
465 def test_realpath_resolve_before_normalizing(self):
466 # Bug #990669: Symbolic links should be resolved before we
467 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
468 # in the following hierarchy:
469 # a/k/y
470 #
471 # and a symbolic link 'link-y' pointing to 'y' in directory 'a',
472 # then realpath("link-y/..") should return 'k', not 'a'.
473 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000474 os.mkdir(ABSTFN)
475 os.mkdir(ABSTFN + "/k")
476 os.mkdir(ABSTFN + "/k/y")
477 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000478
Brian Curtind40e6f72010-07-08 21:39:08 +0000479 # Absolute path.
480 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
481 # Relative path.
Hai Shi598a9512020-08-07 23:18:38 +0800482 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300483 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
484 ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000485 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800486 os_helper.unlink(ABSTFN + "/link-y")
Brian Curtind40e6f72010-07-08 21:39:08 +0000487 safe_rmdir(ABSTFN + "/k/y")
488 safe_rmdir(ABSTFN + "/k")
489 safe_rmdir(ABSTFN)
Tim Peters5d36a552005-06-03 22:40:27 +0000490
Brian Curtin52173d42010-12-02 18:29:18 +0000491 @unittest.skipUnless(hasattr(os, "symlink"),
492 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000493 @skip_if_ABSTFN_contains_backslash
494 def test_realpath_resolve_first(self):
495 # Bug #1213894: The first component of the path, if not absolute,
496 # must be resolved too.
Georg Brandl268e61c2005-06-03 14:28:50 +0000497
Brian Curtind40e6f72010-07-08 21:39:08 +0000498 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000499 os.mkdir(ABSTFN)
500 os.mkdir(ABSTFN + "/k")
501 os.symlink(ABSTFN, ABSTFN + "link")
Hai Shi598a9512020-08-07 23:18:38 +0800502 with os_helper.change_cwd(dirname(ABSTFN)):
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300503 base = basename(ABSTFN)
504 self.assertEqual(realpath(base + "link"), ABSTFN)
505 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000506 finally:
Hai Shi598a9512020-08-07 23:18:38 +0800507 os_helper.unlink(ABSTFN + "link")
Brian Curtind40e6f72010-07-08 21:39:08 +0000508 safe_rmdir(ABSTFN + "/k")
509 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000510
Guido van Rossumd8faa362007-04-27 19:54:29 +0000511 def test_relpath(self):
512 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
513 try:
514 curdir = os.path.split(os.getcwd())[-1]
515 self.assertRaises(ValueError, posixpath.relpath, "")
516 self.assertEqual(posixpath.relpath("a"), "a")
517 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
518 self.assertEqual(posixpath.relpath("a/b"), "a/b")
519 self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
520 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000521 self.assertEqual(posixpath.relpath("a/b", "../c"),
522 "../"+curdir+"/a/b")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000523 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
Christian Heimesfaf2f632008-01-06 16:59:19 +0000524 self.assertEqual(posixpath.relpath("a", "a"), ".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000525 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat')
526 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat')
527 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat')
528 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..')
529 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat')
530 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x')
531 self.assertEqual(posixpath.relpath("/", "/"), '.')
532 self.assertEqual(posixpath.relpath("/a", "/a"), '.')
533 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000534 finally:
535 os.getcwd = real_getcwd
Brett Cannonb47243a2003-06-16 21:54:50 +0000536
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000537 def test_relpath_bytes(self):
538 (real_getcwdb, os.getcwdb) = (os.getcwdb, lambda: br"/home/user/bar")
539 try:
540 curdir = os.path.split(os.getcwdb())[-1]
541 self.assertRaises(ValueError, posixpath.relpath, b"")
542 self.assertEqual(posixpath.relpath(b"a"), b"a")
543 self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a")
544 self.assertEqual(posixpath.relpath(b"a/b"), b"a/b")
545 self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b")
546 self.assertEqual(posixpath.relpath(b"a", b"../b"),
547 b"../"+curdir+b"/a")
548 self.assertEqual(posixpath.relpath(b"a/b", b"../c"),
549 b"../"+curdir+b"/a/b")
550 self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a")
551 self.assertEqual(posixpath.relpath(b"a", b"a"), b".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000552 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat')
553 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat')
554 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat')
555 self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..')
556 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat')
557 self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x')
558 self.assertEqual(posixpath.relpath(b"/", b"/"), b'.')
559 self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.')
560 self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.')
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000561
562 self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str")
563 self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes")
564 finally:
565 os.getcwdb = real_getcwdb
566
Serhiy Storchaka38220932015-03-31 15:31:53 +0300567 def test_commonpath(self):
568 def check(paths, expected):
569 self.assertEqual(posixpath.commonpath(paths), expected)
570 self.assertEqual(posixpath.commonpath([os.fsencode(p) for p in paths]),
571 os.fsencode(expected))
572 def check_error(exc, paths):
573 self.assertRaises(exc, posixpath.commonpath, paths)
574 self.assertRaises(exc, posixpath.commonpath,
575 [os.fsencode(p) for p in paths])
576
577 self.assertRaises(ValueError, posixpath.commonpath, [])
578 check_error(ValueError, ['/usr', 'usr'])
579 check_error(ValueError, ['usr', '/usr'])
580
581 check(['/usr/local'], '/usr/local')
582 check(['/usr/local', '/usr/local'], '/usr/local')
583 check(['/usr/local/', '/usr/local'], '/usr/local')
584 check(['/usr/local/', '/usr/local/'], '/usr/local')
585 check(['/usr//local', '//usr/local'], '/usr/local')
586 check(['/usr/./local', '/./usr/local'], '/usr/local')
587 check(['/', '/dev'], '/')
588 check(['/usr', '/dev'], '/')
589 check(['/usr/lib/', '/usr/lib/python3'], '/usr/lib')
590 check(['/usr/lib/', '/usr/lib64/'], '/usr')
591
592 check(['/usr/lib', '/usr/lib64'], '/usr')
593 check(['/usr/lib/', '/usr/lib64'], '/usr')
594
595 check(['spam'], 'spam')
596 check(['spam', 'spam'], 'spam')
597 check(['spam', 'alot'], '')
598 check(['and/jam', 'and/spam'], 'and')
599 check(['and//jam', 'and/spam//'], 'and')
600 check(['and/./jam', './and/spam'], 'and')
601 check(['and/jam', 'and/spam', 'alot'], '')
602 check(['and/jam', 'and/spam', 'and'], 'and')
603
604 check([''], '')
605 check(['', 'spam/alot'], '')
606 check_error(ValueError, ['', '/spam/alot'])
607
608 self.assertRaises(TypeError, posixpath.commonpath,
609 [b'/usr/lib/', '/usr/lib/python3'])
610 self.assertRaises(TypeError, posixpath.commonpath,
611 [b'/usr/lib/', 'usr/lib/python3'])
612 self.assertRaises(TypeError, posixpath.commonpath,
613 [b'usr/lib/', '/usr/lib/python3'])
614 self.assertRaises(TypeError, posixpath.commonpath,
615 ['/usr/lib/', b'/usr/lib/python3'])
616 self.assertRaises(TypeError, posixpath.commonpath,
617 ['/usr/lib/', b'usr/lib/python3'])
618 self.assertRaises(TypeError, posixpath.commonpath,
619 ['usr/lib/', b'/usr/lib/python3'])
620
Florent Xiclunac9c79782010-03-08 12:24:53 +0000621
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200622class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
Florent Xiclunac9c79782010-03-08 12:24:53 +0000623 pathmodule = posixpath
624 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
625
626
Brett Cannon3f9183b2016-08-26 14:44:48 -0700627class PathLikeTests(unittest.TestCase):
628
629 path = posixpath
630
Brett Cannon3f9183b2016-08-26 14:44:48 -0700631 def setUp(self):
Hai Shi598a9512020-08-07 23:18:38 +0800632 self.file_name = os_helper.TESTFN
633 self.file_path = FakePath(os_helper.TESTFN)
634 self.addCleanup(os_helper.unlink, self.file_name)
Brett Cannon3f9183b2016-08-26 14:44:48 -0700635 with open(self.file_name, 'xb', 0) as file:
636 file.write(b"test_posixpath.PathLikeTests")
637
638 def assertPathEqual(self, func):
639 self.assertEqual(func(self.file_path), func(self.file_name))
640
641 def test_path_normcase(self):
642 self.assertPathEqual(self.path.normcase)
643
644 def test_path_isabs(self):
645 self.assertPathEqual(self.path.isabs)
646
647 def test_path_join(self):
Serhiy Storchakab21d1552018-03-02 11:53:51 +0200648 self.assertEqual(self.path.join('a', FakePath('b'), 'c'),
Brett Cannon3f9183b2016-08-26 14:44:48 -0700649 self.path.join('a', 'b', 'c'))
650
651 def test_path_split(self):
652 self.assertPathEqual(self.path.split)
653
654 def test_path_splitext(self):
655 self.assertPathEqual(self.path.splitext)
656
657 def test_path_splitdrive(self):
658 self.assertPathEqual(self.path.splitdrive)
659
660 def test_path_basename(self):
661 self.assertPathEqual(self.path.basename)
662
663 def test_path_dirname(self):
664 self.assertPathEqual(self.path.dirname)
665
666 def test_path_islink(self):
667 self.assertPathEqual(self.path.islink)
668
669 def test_path_lexists(self):
670 self.assertPathEqual(self.path.lexists)
671
672 def test_path_ismount(self):
673 self.assertPathEqual(self.path.ismount)
674
675 def test_path_expanduser(self):
676 self.assertPathEqual(self.path.expanduser)
677
678 def test_path_expandvars(self):
679 self.assertPathEqual(self.path.expandvars)
680
681 def test_path_normpath(self):
682 self.assertPathEqual(self.path.normpath)
683
684 def test_path_abspath(self):
685 self.assertPathEqual(self.path.abspath)
686
687 def test_path_realpath(self):
688 self.assertPathEqual(self.path.realpath)
689
690 def test_path_relpath(self):
691 self.assertPathEqual(self.path.relpath)
692
693 def test_path_commonpath(self):
694 common_path = self.path.commonpath([self.file_path, self.file_name])
695 self.assertEqual(common_path, self.file_name)
696
697
Brett Cannonb47243a2003-06-16 21:54:50 +0000698if __name__=="__main__":
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200699 unittest.main()