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