blob: ae59ef5927be84f943a710cdc8a787aa5f0bb77b [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
4import warnings
Georg Brandl89fad142010-03-14 10:23:39 +00005from posixpath import realpath, abspath, dirname, basename
Victor Stinner1ab6c2d2011-11-15 22:27:41 +01006from test import support, test_genericpath
Serhiy Storchakab21d1552018-03-02 11:53:51 +02007from test.support import FakePath
Johannes Gijsbers4ec40642004-08-14 15:01:53 +00008
Michael Foord07926f02011-03-16 17:19:16 -04009try:
10 import posix
11except ImportError:
12 posix = None
13
Johannes Gijsbers4ec40642004-08-14 15:01:53 +000014# An absolute path to a temporary filename for testing. We can't rely on TESTFN
15# being an absolute path, so we need this.
16
Benjamin Petersonee8712c2008-05-20 21:35:26 +000017ABSTFN = abspath(support.TESTFN)
Skip Montanaroe809b002000-07-12 00:20:08 +000018
Brian Curtind40e6f72010-07-08 21:39:08 +000019def skip_if_ABSTFN_contains_backslash(test):
20 """
21 On Windows, posixpath.abspath still returns paths with backslashes
22 instead of posix forward slashes. If this is the case, several tests
23 fail, so skip them.
24 """
25 found_backslash = '\\' in ABSTFN
26 msg = "ABSTFN is not a posix path - tests fail"
27 return [test, unittest.skip(msg)(test)][found_backslash]
28
Guido van Rossumd8faa362007-04-27 19:54:29 +000029def safe_rmdir(dirname):
30 try:
31 os.rmdir(dirname)
32 except OSError:
33 pass
34
Brett Cannonb47243a2003-06-16 21:54:50 +000035class PosixPathTest(unittest.TestCase):
Skip Montanaroe809b002000-07-12 00:20:08 +000036
Guido van Rossumd8faa362007-04-27 19:54:29 +000037 def setUp(self):
38 self.tearDown()
39
40 def tearDown(self):
41 for suffix in ["", "1", "2"]:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000042 support.unlink(support.TESTFN + suffix)
43 safe_rmdir(support.TESTFN + suffix)
Guido van Rossumd8faa362007-04-27 19:54:29 +000044
Brett Cannonb47243a2003-06-16 21:54:50 +000045 def test_join(self):
Guido van Rossumf0af3e32008-10-02 18:55:37 +000046 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"),
47 "/bar/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +000048 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
Guido van Rossumf0af3e32008-10-02 18:55:37 +000049 self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"),
50 "/foo/bar/baz/")
51
52 self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"),
53 b"/bar/baz")
54 self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"),
55 b"/foo/bar/baz")
56 self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"),
57 b"/foo/bar/baz/")
Skip Montanaroe809b002000-07-12 00:20:08 +000058
Brett Cannonb47243a2003-06-16 21:54:50 +000059 def test_split(self):
60 self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
61 self.assertEqual(posixpath.split("/"), ("/", ""))
62 self.assertEqual(posixpath.split("foo"), ("", "foo"))
63 self.assertEqual(posixpath.split("////foo"), ("////", "foo"))
64 self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar"))
65
Guido van Rossumf0af3e32008-10-02 18:55:37 +000066 self.assertEqual(posixpath.split(b"/foo/bar"), (b"/foo", b"bar"))
67 self.assertEqual(posixpath.split(b"/"), (b"/", b""))
68 self.assertEqual(posixpath.split(b"foo"), (b"", b"foo"))
69 self.assertEqual(posixpath.split(b"////foo"), (b"////", b"foo"))
70 self.assertEqual(posixpath.split(b"//foo//bar"), (b"//foo", b"bar"))
71
Guido van Rossumd8faa362007-04-27 19:54:29 +000072 def splitextTest(self, path, filename, ext):
73 self.assertEqual(posixpath.splitext(path), (filename, ext))
74 self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext))
Guido van Rossumf0af3e32008-10-02 18:55:37 +000075 self.assertEqual(posixpath.splitext("abc/" + path),
76 ("abc/" + filename, ext))
77 self.assertEqual(posixpath.splitext("abc.def/" + path),
78 ("abc.def/" + filename, ext))
79 self.assertEqual(posixpath.splitext("/abc.def/" + path),
80 ("/abc.def/" + filename, ext))
81 self.assertEqual(posixpath.splitext(path + "/"),
82 (filename + ext + "/", ""))
83
84 path = bytes(path, "ASCII")
85 filename = bytes(filename, "ASCII")
86 ext = bytes(ext, "ASCII")
87
88 self.assertEqual(posixpath.splitext(path), (filename, ext))
89 self.assertEqual(posixpath.splitext(b"/" + path),
90 (b"/" + filename, ext))
91 self.assertEqual(posixpath.splitext(b"abc/" + path),
92 (b"abc/" + filename, ext))
93 self.assertEqual(posixpath.splitext(b"abc.def/" + path),
94 (b"abc.def/" + filename, ext))
95 self.assertEqual(posixpath.splitext(b"/abc.def/" + path),
96 (b"/abc.def/" + filename, ext))
97 self.assertEqual(posixpath.splitext(path + b"/"),
98 (filename + ext + b"/", b""))
Brett Cannonb47243a2003-06-16 21:54:50 +000099
Guido van Rossumd8faa362007-04-27 19:54:29 +0000100 def test_splitext(self):
101 self.splitextTest("foo.bar", "foo", ".bar")
102 self.splitextTest("foo.boo.bar", "foo.boo", ".bar")
103 self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar")
104 self.splitextTest(".csh.rc", ".csh", ".rc")
105 self.splitextTest("nodots", "nodots", "")
106 self.splitextTest(".cshrc", ".cshrc", "")
107 self.splitextTest("...manydots", "...manydots", "")
108 self.splitextTest("...manydots.ext", "...manydots", ".ext")
109 self.splitextTest(".", ".", "")
110 self.splitextTest("..", "..", "")
111 self.splitextTest("........", "........", "")
112 self.splitextTest("", "", "")
Brett Cannonb47243a2003-06-16 21:54:50 +0000113
114 def test_isabs(self):
115 self.assertIs(posixpath.isabs(""), False)
116 self.assertIs(posixpath.isabs("/"), True)
117 self.assertIs(posixpath.isabs("/foo"), True)
118 self.assertIs(posixpath.isabs("/foo/bar"), True)
119 self.assertIs(posixpath.isabs("foo/bar"), False)
120
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000121 self.assertIs(posixpath.isabs(b""), False)
122 self.assertIs(posixpath.isabs(b"/"), True)
123 self.assertIs(posixpath.isabs(b"/foo"), True)
124 self.assertIs(posixpath.isabs(b"/foo/bar"), True)
125 self.assertIs(posixpath.isabs(b"foo/bar"), False)
126
Brett Cannonb47243a2003-06-16 21:54:50 +0000127 def test_basename(self):
128 self.assertEqual(posixpath.basename("/foo/bar"), "bar")
129 self.assertEqual(posixpath.basename("/"), "")
130 self.assertEqual(posixpath.basename("foo"), "foo")
131 self.assertEqual(posixpath.basename("////foo"), "foo")
132 self.assertEqual(posixpath.basename("//foo//bar"), "bar")
133
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000134 self.assertEqual(posixpath.basename(b"/foo/bar"), b"bar")
135 self.assertEqual(posixpath.basename(b"/"), b"")
136 self.assertEqual(posixpath.basename(b"foo"), b"foo")
137 self.assertEqual(posixpath.basename(b"////foo"), b"foo")
138 self.assertEqual(posixpath.basename(b"//foo//bar"), b"bar")
139
Brett Cannonb47243a2003-06-16 21:54:50 +0000140 def test_dirname(self):
141 self.assertEqual(posixpath.dirname("/foo/bar"), "/foo")
142 self.assertEqual(posixpath.dirname("/"), "/")
143 self.assertEqual(posixpath.dirname("foo"), "")
144 self.assertEqual(posixpath.dirname("////foo"), "////")
145 self.assertEqual(posixpath.dirname("//foo//bar"), "//foo")
146
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000147 self.assertEqual(posixpath.dirname(b"/foo/bar"), b"/foo")
148 self.assertEqual(posixpath.dirname(b"/"), b"/")
149 self.assertEqual(posixpath.dirname(b"foo"), b"")
150 self.assertEqual(posixpath.dirname(b"////foo"), b"////")
151 self.assertEqual(posixpath.dirname(b"//foo//bar"), b"//foo")
152
Brett Cannonb47243a2003-06-16 21:54:50 +0000153 def test_islink(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000154 self.assertIs(posixpath.islink(support.TESTFN + "1"), False)
Michael Foord07926f02011-03-16 17:19:16 -0400155 self.assertIs(posixpath.lexists(support.TESTFN + "2"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300156
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300157 with open(support.TESTFN + "1", "wb") as f:
Guido van Rossum7dcb8442007-08-27 23:26:56 +0000158 f.write(b"foo")
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300159 self.assertIs(posixpath.islink(support.TESTFN + "1"), False)
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300160
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300161 if support.can_symlink():
162 os.symlink(support.TESTFN + "1", support.TESTFN + "2")
163 self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
164 os.remove(support.TESTFN + "1")
165 self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
166 self.assertIs(posixpath.exists(support.TESTFN + "2"), False)
167 self.assertIs(posixpath.lexists(support.TESTFN + "2"), True)
Brett Cannonb47243a2003-06-16 21:54:50 +0000168
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300169 self.assertIs(posixpath.islink(support.TESTFN + "\udfff"), False)
170 self.assertIs(posixpath.islink(os.fsencode(support.TESTFN) + b"\xff"), False)
171 self.assertIs(posixpath.islink(support.TESTFN + "\x00"), False)
172 self.assertIs(posixpath.islink(os.fsencode(support.TESTFN) + b"\x00"), False)
173
Brett Cannonb47243a2003-06-16 21:54:50 +0000174 def test_ismount(self):
175 self.assertIs(posixpath.ismount("/"), True)
Serhiy Storchaka17a00882018-06-16 13:25:55 +0300176 self.assertIs(posixpath.ismount(b"/"), True)
Michael Foord07926f02011-03-16 17:19:16 -0400177
178 def test_ismount_non_existent(self):
179 # Non-existent mountpoint.
180 self.assertIs(posixpath.ismount(ABSTFN), False)
181 try:
182 os.mkdir(ABSTFN)
183 self.assertIs(posixpath.ismount(ABSTFN), False)
184 finally:
185 safe_rmdir(ABSTFN)
186
Serhiy Storchaka0185f342018-09-18 11:28:51 +0300187 self.assertIs(posixpath.ismount('/\udfff'), False)
188 self.assertIs(posixpath.ismount(b'/\xff'), False)
189 self.assertIs(posixpath.ismount('/\x00'), False)
190 self.assertIs(posixpath.ismount(b'/\x00'), False)
191
Michael Foord07926f02011-03-16 17:19:16 -0400192 @unittest.skipUnless(support.can_symlink(),
193 "Test requires symlink support")
194 def test_ismount_symlinks(self):
195 # Symlinks are never mountpoints.
196 try:
197 os.symlink("/", ABSTFN)
198 self.assertIs(posixpath.ismount(ABSTFN), False)
199 finally:
200 os.unlink(ABSTFN)
201
202 @unittest.skipIf(posix is None, "Test requires posix module")
203 def test_ismount_different_device(self):
204 # Simulate the path being on a different device from its parent by
205 # mocking out st_dev.
206 save_lstat = os.lstat
207 def fake_lstat(path):
208 st_ino = 0
209 st_dev = 0
210 if path == ABSTFN:
211 st_dev = 1
212 st_ino = 1
213 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
214 try:
215 os.lstat = fake_lstat
216 self.assertIs(posixpath.ismount(ABSTFN), True)
217 finally:
218 os.lstat = save_lstat
Brett Cannonb47243a2003-06-16 21:54:50 +0000219
R David Murray750018b2016-08-18 21:27:48 -0400220 @unittest.skipIf(posix is None, "Test requires posix module")
221 def test_ismount_directory_not_readable(self):
222 # issue #2466: Simulate ismount run on a directory that is not
223 # readable, which used to return False.
224 save_lstat = os.lstat
225 def fake_lstat(path):
226 st_ino = 0
227 st_dev = 0
228 if path.startswith(ABSTFN) and path != ABSTFN:
229 # ismount tries to read something inside the ABSTFN directory;
230 # simulate this being forbidden (no read permission).
231 raise OSError("Fake [Errno 13] Permission denied")
232 if path == ABSTFN:
233 st_dev = 1
234 st_ino = 1
235 return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
236 try:
237 os.lstat = fake_lstat
238 self.assertIs(posixpath.ismount(ABSTFN), True)
239 finally:
240 os.lstat = save_lstat
241
Brett Cannonb47243a2003-06-16 21:54:50 +0000242 def test_expanduser(self):
243 self.assertEqual(posixpath.expanduser("foo"), "foo")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000244 self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
Serhiy Storchakaa3fd0b22016-05-03 21:17:03 +0300245 with support.EnvironmentVarGuard() as env:
246 for home in '/', '', '//', '///':
247 with self.subTest(home=home):
248 env['HOME'] = home
249 self.assertEqual(posixpath.expanduser("~"), "/")
250 self.assertEqual(posixpath.expanduser("~/"), "/")
251 self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
Brett Cannonb47243a2003-06-16 21:54:50 +0000252 try:
253 import pwd
254 except ImportError:
255 pass
256 else:
Ezio Melottie9615932010-01-24 19:26:24 +0000257 self.assertIsInstance(posixpath.expanduser("~/"), str)
258 self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
Neal Norwitz168e73d2003-07-01 03:33:31 +0000259 # if home directory == root directory, this test makes no sense
260 if posixpath.expanduser("~") != '/':
261 self.assertEqual(
262 posixpath.expanduser("~") + "/",
263 posixpath.expanduser("~/")
264 )
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000265 self.assertEqual(
266 posixpath.expanduser(b"~") + b"/",
267 posixpath.expanduser(b"~/")
268 )
Ezio Melottie9615932010-01-24 19:26:24 +0000269 self.assertIsInstance(posixpath.expanduser("~root/"), str)
270 self.assertIsInstance(posixpath.expanduser("~foo/"), str)
271 self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
272 self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
Brett Cannonb47243a2003-06-16 21:54:50 +0000273
Hirokazu Yamamoto71959632009-04-27 01:44:28 +0000274 with support.EnvironmentVarGuard() as env:
Michael Foord07926f02011-03-16 17:19:16 -0400275 # expanduser should fall back to using the password database
276 del env['HOME']
277 home = pwd.getpwuid(os.getuid()).pw_dir
Ezio Melottice82d572013-05-09 15:19:45 +0300278 # $HOME can end with a trailing /, so strip it (see #17809)
Serhiy Storchakaa3fd0b22016-05-03 21:17:03 +0300279 home = home.rstrip("/") or '/'
280 self.assertEqual(posixpath.expanduser("~"), home)
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000281
Brett Cannonb47243a2003-06-16 21:54:50 +0000282 def test_normpath(self):
283 self.assertEqual(posixpath.normpath(""), ".")
284 self.assertEqual(posixpath.normpath("/"), "/")
285 self.assertEqual(posixpath.normpath("//"), "//")
286 self.assertEqual(posixpath.normpath("///"), "/")
287 self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000288 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"),
289 "/foo/baz")
Brett Cannonb47243a2003-06-16 21:54:50 +0000290 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
291
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000292 self.assertEqual(posixpath.normpath(b""), b".")
293 self.assertEqual(posixpath.normpath(b"/"), b"/")
294 self.assertEqual(posixpath.normpath(b"//"), b"//")
295 self.assertEqual(posixpath.normpath(b"///"), b"/")
296 self.assertEqual(posixpath.normpath(b"///foo/.//bar//"), b"/foo/bar")
297 self.assertEqual(posixpath.normpath(b"///foo/.//bar//.//..//.//baz"),
298 b"/foo/baz")
299 self.assertEqual(posixpath.normpath(b"///..//./foo/.//bar"),
300 b"/foo/bar")
301
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200302 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200303 def test_realpath_curdir(self):
304 self.assertEqual(realpath('.'), os.getcwd())
305 self.assertEqual(realpath('./.'), os.getcwd())
306 self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
307
308 self.assertEqual(realpath(b'.'), os.getcwdb())
309 self.assertEqual(realpath(b'./.'), os.getcwdb())
310 self.assertEqual(realpath(b'/'.join([b'.'] * 100)), os.getcwdb())
311
Serhiy Storchaka1548ed62013-02-18 13:32:30 +0200312 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka467393d2013-02-18 12:21:04 +0200313 def test_realpath_pardir(self):
314 self.assertEqual(realpath('..'), dirname(os.getcwd()))
315 self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
316 self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
317
318 self.assertEqual(realpath(b'..'), dirname(os.getcwdb()))
319 self.assertEqual(realpath(b'../..'), dirname(dirname(os.getcwdb())))
320 self.assertEqual(realpath(b'/'.join([b'..'] * 100)), b'/')
321
Brian Curtin52173d42010-12-02 18:29:18 +0000322 @unittest.skipUnless(hasattr(os, "symlink"),
323 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000324 @skip_if_ABSTFN_contains_backslash
325 def test_realpath_basic(self):
326 # Basic operation.
327 try:
328 os.symlink(ABSTFN+"1", ABSTFN)
329 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
330 finally:
331 support.unlink(ABSTFN)
Tim Petersa45cacf2004-08-20 03:47:14 +0000332
Brian Curtin52173d42010-12-02 18:29:18 +0000333 @unittest.skipUnless(hasattr(os, "symlink"),
334 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000335 @skip_if_ABSTFN_contains_backslash
Michael Foord07926f02011-03-16 17:19:16 -0400336 def test_realpath_relative(self):
337 try:
338 os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
339 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
340 finally:
341 support.unlink(ABSTFN)
342
343 @unittest.skipUnless(hasattr(os, "symlink"),
344 "Missing symlink implementation")
345 @skip_if_ABSTFN_contains_backslash
Brian Curtind40e6f72010-07-08 21:39:08 +0000346 def test_realpath_symlink_loops(self):
347 # Bug #930024, return the path unchanged if we get into an infinite
348 # symlink loop.
349 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000350 os.symlink(ABSTFN, ABSTFN)
351 self.assertEqual(realpath(ABSTFN), ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000352
Brian Curtind40e6f72010-07-08 21:39:08 +0000353 os.symlink(ABSTFN+"1", ABSTFN+"2")
354 os.symlink(ABSTFN+"2", ABSTFN+"1")
355 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
356 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000357
Serhiy Storchakadf326912013-02-10 12:22:07 +0200358 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
359 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
360 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
361 os.symlink(ABSTFN+"x", ABSTFN+"y")
362 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
363 ABSTFN + "y")
364 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
365 ABSTFN + "1")
366
367 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
368 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
369
370 os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
371 basename(ABSTFN) + "c", ABSTFN+"c")
372 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
373
Brian Curtind40e6f72010-07-08 21:39:08 +0000374 # Test using relative path as well.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300375 with support.change_cwd(dirname(ABSTFN)):
376 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
Brian Curtind40e6f72010-07-08 21:39:08 +0000377 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000378 support.unlink(ABSTFN)
379 support.unlink(ABSTFN+"1")
380 support.unlink(ABSTFN+"2")
Serhiy Storchakadf326912013-02-10 12:22:07 +0200381 support.unlink(ABSTFN+"y")
382 support.unlink(ABSTFN+"c")
Ezio Melotti136726c2013-03-01 20:59:17 +0200383 support.unlink(ABSTFN+"a")
Serhiy Storchakadf326912013-02-10 12:22:07 +0200384
385 @unittest.skipUnless(hasattr(os, "symlink"),
386 "Missing symlink implementation")
387 @skip_if_ABSTFN_contains_backslash
388 def test_realpath_repeated_indirect_symlinks(self):
389 # Issue #6975.
390 try:
391 os.mkdir(ABSTFN)
392 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
393 os.symlink('self/self/self', ABSTFN + '/link')
394 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
395 finally:
396 support.unlink(ABSTFN + '/self')
397 support.unlink(ABSTFN + '/link')
398 safe_rmdir(ABSTFN)
399
400 @unittest.skipUnless(hasattr(os, "symlink"),
401 "Missing symlink implementation")
402 @skip_if_ABSTFN_contains_backslash
403 def test_realpath_deep_recursion(self):
404 depth = 10
Serhiy Storchakadf326912013-02-10 12:22:07 +0200405 try:
406 os.mkdir(ABSTFN)
407 for i in range(depth):
408 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
409 os.symlink('.', ABSTFN + '/0')
410 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
411
412 # Test using relative path as well.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300413 with support.change_cwd(ABSTFN):
414 self.assertEqual(realpath('%d' % depth), ABSTFN)
Serhiy Storchakadf326912013-02-10 12:22:07 +0200415 finally:
Serhiy Storchakadf326912013-02-10 12:22:07 +0200416 for i in range(depth + 1):
417 support.unlink(ABSTFN + '/%d' % i)
418 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000419
Brian Curtin52173d42010-12-02 18:29:18 +0000420 @unittest.skipUnless(hasattr(os, "symlink"),
421 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000422 @skip_if_ABSTFN_contains_backslash
423 def test_realpath_resolve_parents(self):
424 # We also need to resolve any symlinks in the parents of a relative
425 # path passed to realpath. E.g.: current working directory is
426 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
427 # realpath("a"). This should return /usr/share/doc/a/.
428 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000429 os.mkdir(ABSTFN)
430 os.mkdir(ABSTFN + "/y")
431 os.symlink(ABSTFN + "/y", ABSTFN + "/k")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000432
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300433 with support.change_cwd(ABSTFN + "/k"):
434 self.assertEqual(realpath("a"), ABSTFN + "/y/a")
Brian Curtind40e6f72010-07-08 21:39:08 +0000435 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000436 support.unlink(ABSTFN + "/k")
437 safe_rmdir(ABSTFN + "/y")
438 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000439
Brian Curtin52173d42010-12-02 18:29:18 +0000440 @unittest.skipUnless(hasattr(os, "symlink"),
441 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000442 @skip_if_ABSTFN_contains_backslash
443 def test_realpath_resolve_before_normalizing(self):
444 # Bug #990669: Symbolic links should be resolved before we
445 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
446 # in the following hierarchy:
447 # a/k/y
448 #
449 # and a symbolic link 'link-y' pointing to 'y' in directory 'a',
450 # then realpath("link-y/..") should return 'k', not 'a'.
451 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000452 os.mkdir(ABSTFN)
453 os.mkdir(ABSTFN + "/k")
454 os.mkdir(ABSTFN + "/k/y")
455 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000456
Brian Curtind40e6f72010-07-08 21:39:08 +0000457 # Absolute path.
458 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
459 # Relative path.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300460 with support.change_cwd(dirname(ABSTFN)):
461 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
462 ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000463 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000464 support.unlink(ABSTFN + "/link-y")
465 safe_rmdir(ABSTFN + "/k/y")
466 safe_rmdir(ABSTFN + "/k")
467 safe_rmdir(ABSTFN)
Tim Peters5d36a552005-06-03 22:40:27 +0000468
Brian Curtin52173d42010-12-02 18:29:18 +0000469 @unittest.skipUnless(hasattr(os, "symlink"),
470 "Missing symlink implementation")
Brian Curtind40e6f72010-07-08 21:39:08 +0000471 @skip_if_ABSTFN_contains_backslash
472 def test_realpath_resolve_first(self):
473 # Bug #1213894: The first component of the path, if not absolute,
474 # must be resolved too.
Georg Brandl268e61c2005-06-03 14:28:50 +0000475
Brian Curtind40e6f72010-07-08 21:39:08 +0000476 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000477 os.mkdir(ABSTFN)
478 os.mkdir(ABSTFN + "/k")
479 os.symlink(ABSTFN, ABSTFN + "link")
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300480 with support.change_cwd(dirname(ABSTFN)):
481 base = basename(ABSTFN)
482 self.assertEqual(realpath(base + "link"), ABSTFN)
483 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
Brian Curtind40e6f72010-07-08 21:39:08 +0000484 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000485 support.unlink(ABSTFN + "link")
486 safe_rmdir(ABSTFN + "/k")
487 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000488
Guido van Rossumd8faa362007-04-27 19:54:29 +0000489 def test_relpath(self):
490 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
491 try:
492 curdir = os.path.split(os.getcwd())[-1]
493 self.assertRaises(ValueError, posixpath.relpath, "")
494 self.assertEqual(posixpath.relpath("a"), "a")
495 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
496 self.assertEqual(posixpath.relpath("a/b"), "a/b")
497 self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
498 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000499 self.assertEqual(posixpath.relpath("a/b", "../c"),
500 "../"+curdir+"/a/b")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000501 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
Christian Heimesfaf2f632008-01-06 16:59:19 +0000502 self.assertEqual(posixpath.relpath("a", "a"), ".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000503 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat')
504 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat')
505 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat')
506 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..')
507 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat')
508 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x')
509 self.assertEqual(posixpath.relpath("/", "/"), '.')
510 self.assertEqual(posixpath.relpath("/a", "/a"), '.')
511 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000512 finally:
513 os.getcwd = real_getcwd
Brett Cannonb47243a2003-06-16 21:54:50 +0000514
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000515 def test_relpath_bytes(self):
516 (real_getcwdb, os.getcwdb) = (os.getcwdb, lambda: br"/home/user/bar")
517 try:
518 curdir = os.path.split(os.getcwdb())[-1]
519 self.assertRaises(ValueError, posixpath.relpath, b"")
520 self.assertEqual(posixpath.relpath(b"a"), b"a")
521 self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a")
522 self.assertEqual(posixpath.relpath(b"a/b"), b"a/b")
523 self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b")
524 self.assertEqual(posixpath.relpath(b"a", b"../b"),
525 b"../"+curdir+b"/a")
526 self.assertEqual(posixpath.relpath(b"a/b", b"../c"),
527 b"../"+curdir+b"/a/b")
528 self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a")
529 self.assertEqual(posixpath.relpath(b"a", b"a"), b".")
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000530 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat')
531 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat')
532 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat')
533 self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..')
534 self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat')
535 self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x')
536 self.assertEqual(posixpath.relpath(b"/", b"/"), b'.')
537 self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.')
538 self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.')
Guido van Rossumf0af3e32008-10-02 18:55:37 +0000539
540 self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str")
541 self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes")
542 finally:
543 os.getcwdb = real_getcwdb
544
Serhiy Storchaka38220932015-03-31 15:31:53 +0300545 def test_commonpath(self):
546 def check(paths, expected):
547 self.assertEqual(posixpath.commonpath(paths), expected)
548 self.assertEqual(posixpath.commonpath([os.fsencode(p) for p in paths]),
549 os.fsencode(expected))
550 def check_error(exc, paths):
551 self.assertRaises(exc, posixpath.commonpath, paths)
552 self.assertRaises(exc, posixpath.commonpath,
553 [os.fsencode(p) for p in paths])
554
555 self.assertRaises(ValueError, posixpath.commonpath, [])
556 check_error(ValueError, ['/usr', 'usr'])
557 check_error(ValueError, ['usr', '/usr'])
558
559 check(['/usr/local'], '/usr/local')
560 check(['/usr/local', '/usr/local'], '/usr/local')
561 check(['/usr/local/', '/usr/local'], '/usr/local')
562 check(['/usr/local/', '/usr/local/'], '/usr/local')
563 check(['/usr//local', '//usr/local'], '/usr/local')
564 check(['/usr/./local', '/./usr/local'], '/usr/local')
565 check(['/', '/dev'], '/')
566 check(['/usr', '/dev'], '/')
567 check(['/usr/lib/', '/usr/lib/python3'], '/usr/lib')
568 check(['/usr/lib/', '/usr/lib64/'], '/usr')
569
570 check(['/usr/lib', '/usr/lib64'], '/usr')
571 check(['/usr/lib/', '/usr/lib64'], '/usr')
572
573 check(['spam'], 'spam')
574 check(['spam', 'spam'], 'spam')
575 check(['spam', 'alot'], '')
576 check(['and/jam', 'and/spam'], 'and')
577 check(['and//jam', 'and/spam//'], 'and')
578 check(['and/./jam', './and/spam'], 'and')
579 check(['and/jam', 'and/spam', 'alot'], '')
580 check(['and/jam', 'and/spam', 'and'], 'and')
581
582 check([''], '')
583 check(['', 'spam/alot'], '')
584 check_error(ValueError, ['', '/spam/alot'])
585
586 self.assertRaises(TypeError, posixpath.commonpath,
587 [b'/usr/lib/', '/usr/lib/python3'])
588 self.assertRaises(TypeError, posixpath.commonpath,
589 [b'/usr/lib/', 'usr/lib/python3'])
590 self.assertRaises(TypeError, posixpath.commonpath,
591 [b'usr/lib/', '/usr/lib/python3'])
592 self.assertRaises(TypeError, posixpath.commonpath,
593 ['/usr/lib/', b'/usr/lib/python3'])
594 self.assertRaises(TypeError, posixpath.commonpath,
595 ['/usr/lib/', b'usr/lib/python3'])
596 self.assertRaises(TypeError, posixpath.commonpath,
597 ['usr/lib/', b'/usr/lib/python3'])
598
Florent Xiclunac9c79782010-03-08 12:24:53 +0000599
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200600class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
Florent Xiclunac9c79782010-03-08 12:24:53 +0000601 pathmodule = posixpath
602 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
603
604
Brett Cannon3f9183b2016-08-26 14:44:48 -0700605class PathLikeTests(unittest.TestCase):
606
607 path = posixpath
608
Brett Cannon3f9183b2016-08-26 14:44:48 -0700609 def setUp(self):
610 self.file_name = support.TESTFN.lower()
Serhiy Storchakab21d1552018-03-02 11:53:51 +0200611 self.file_path = FakePath(support.TESTFN)
Brett Cannon3f9183b2016-08-26 14:44:48 -0700612 self.addCleanup(support.unlink, self.file_name)
613 with open(self.file_name, 'xb', 0) as file:
614 file.write(b"test_posixpath.PathLikeTests")
615
616 def assertPathEqual(self, func):
617 self.assertEqual(func(self.file_path), func(self.file_name))
618
619 def test_path_normcase(self):
620 self.assertPathEqual(self.path.normcase)
621
622 def test_path_isabs(self):
623 self.assertPathEqual(self.path.isabs)
624
625 def test_path_join(self):
Serhiy Storchakab21d1552018-03-02 11:53:51 +0200626 self.assertEqual(self.path.join('a', FakePath('b'), 'c'),
Brett Cannon3f9183b2016-08-26 14:44:48 -0700627 self.path.join('a', 'b', 'c'))
628
629 def test_path_split(self):
630 self.assertPathEqual(self.path.split)
631
632 def test_path_splitext(self):
633 self.assertPathEqual(self.path.splitext)
634
635 def test_path_splitdrive(self):
636 self.assertPathEqual(self.path.splitdrive)
637
638 def test_path_basename(self):
639 self.assertPathEqual(self.path.basename)
640
641 def test_path_dirname(self):
642 self.assertPathEqual(self.path.dirname)
643
644 def test_path_islink(self):
645 self.assertPathEqual(self.path.islink)
646
647 def test_path_lexists(self):
648 self.assertPathEqual(self.path.lexists)
649
650 def test_path_ismount(self):
651 self.assertPathEqual(self.path.ismount)
652
653 def test_path_expanduser(self):
654 self.assertPathEqual(self.path.expanduser)
655
656 def test_path_expandvars(self):
657 self.assertPathEqual(self.path.expandvars)
658
659 def test_path_normpath(self):
660 self.assertPathEqual(self.path.normpath)
661
662 def test_path_abspath(self):
663 self.assertPathEqual(self.path.abspath)
664
665 def test_path_realpath(self):
666 self.assertPathEqual(self.path.realpath)
667
668 def test_path_relpath(self):
669 self.assertPathEqual(self.path.relpath)
670
671 def test_path_commonpath(self):
672 common_path = self.path.commonpath([self.file_path, self.file_name])
673 self.assertEqual(common_path, self.file_name)
674
675
Brett Cannonb47243a2003-06-16 21:54:50 +0000676if __name__=="__main__":
Ezio Melottid0dfe9a2013-01-10 03:12:50 +0200677 unittest.main()