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