|
1 import unittest |
|
2 from test import test_support |
|
3 |
|
4 import posixpath, os |
|
5 from posixpath import realpath, abspath, join, dirname, basename |
|
6 |
|
7 # An absolute path to a temporary filename for testing. We can't rely on TESTFN |
|
8 # being an absolute path, so we need this. |
|
9 |
|
10 ABSTFN = abspath(test_support.TESTFN) |
|
11 |
|
12 class PosixPathTest(unittest.TestCase): |
|
13 |
|
14 def assertIs(self, a, b): |
|
15 self.assert_(a is b) |
|
16 |
|
17 def test_normcase(self): |
|
18 # Check that normcase() is idempotent |
|
19 p = "FoO/./BaR" |
|
20 p = posixpath.normcase(p) |
|
21 self.assertEqual(p, posixpath.normcase(p)) |
|
22 |
|
23 self.assertRaises(TypeError, posixpath.normcase) |
|
24 |
|
25 def test_join(self): |
|
26 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"), "/bar/baz") |
|
27 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz") |
|
28 self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"), "/foo/bar/baz/") |
|
29 |
|
30 self.assertRaises(TypeError, posixpath.join) |
|
31 |
|
32 def test_splitdrive(self): |
|
33 self.assertEqual(posixpath.splitdrive("/foo/bar"), ("", "/foo/bar")) |
|
34 |
|
35 self.assertRaises(TypeError, posixpath.splitdrive) |
|
36 |
|
37 def test_split(self): |
|
38 self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) |
|
39 self.assertEqual(posixpath.split("/"), ("/", "")) |
|
40 self.assertEqual(posixpath.split("foo"), ("", "foo")) |
|
41 self.assertEqual(posixpath.split("////foo"), ("////", "foo")) |
|
42 self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar")) |
|
43 |
|
44 self.assertRaises(TypeError, posixpath.split) |
|
45 |
|
46 def test_splitext(self): |
|
47 self.assertEqual(posixpath.splitext("foo.ext"), ("foo", ".ext")) |
|
48 self.assertEqual(posixpath.splitext("/foo/foo.ext"), ("/foo/foo", ".ext")) |
|
49 self.assertEqual(posixpath.splitext(".ext"), ("", ".ext")) |
|
50 self.assertEqual(posixpath.splitext("/foo.ext/foo"), ("/foo.ext/foo", "")) |
|
51 self.assertEqual(posixpath.splitext("foo.ext/"), ("foo.ext/", "")) |
|
52 self.assertEqual(posixpath.splitext(""), ("", "")) |
|
53 self.assertEqual(posixpath.splitext("foo.bar.ext"), ("foo.bar", ".ext")) |
|
54 |
|
55 self.assertRaises(TypeError, posixpath.splitext) |
|
56 |
|
57 def test_isabs(self): |
|
58 self.assertIs(posixpath.isabs(""), False) |
|
59 self.assertIs(posixpath.isabs("/"), True) |
|
60 self.assertIs(posixpath.isabs("/foo"), True) |
|
61 self.assertIs(posixpath.isabs("/foo/bar"), True) |
|
62 self.assertIs(posixpath.isabs("foo/bar"), False) |
|
63 |
|
64 self.assertRaises(TypeError, posixpath.isabs) |
|
65 |
|
66 def test_splitdrive(self): |
|
67 self.assertEqual(posixpath.splitdrive("/foo/bar"), ("", "/foo/bar")) |
|
68 |
|
69 self.assertRaises(TypeError, posixpath.splitdrive) |
|
70 |
|
71 def test_basename(self): |
|
72 self.assertEqual(posixpath.basename("/foo/bar"), "bar") |
|
73 self.assertEqual(posixpath.basename("/"), "") |
|
74 self.assertEqual(posixpath.basename("foo"), "foo") |
|
75 self.assertEqual(posixpath.basename("////foo"), "foo") |
|
76 self.assertEqual(posixpath.basename("//foo//bar"), "bar") |
|
77 |
|
78 self.assertRaises(TypeError, posixpath.basename) |
|
79 |
|
80 def test_dirname(self): |
|
81 self.assertEqual(posixpath.dirname("/foo/bar"), "/foo") |
|
82 self.assertEqual(posixpath.dirname("/"), "/") |
|
83 self.assertEqual(posixpath.dirname("foo"), "") |
|
84 self.assertEqual(posixpath.dirname("////foo"), "////") |
|
85 self.assertEqual(posixpath.dirname("//foo//bar"), "//foo") |
|
86 |
|
87 self.assertRaises(TypeError, posixpath.dirname) |
|
88 |
|
89 def test_commonprefix(self): |
|
90 self.assertEqual( |
|
91 posixpath.commonprefix([]), |
|
92 "" |
|
93 ) |
|
94 self.assertEqual( |
|
95 posixpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"]), |
|
96 "/home/swen" |
|
97 ) |
|
98 self.assertEqual( |
|
99 posixpath.commonprefix(["/home/swen/spam", "/home/swen/eggs"]), |
|
100 "/home/swen/" |
|
101 ) |
|
102 self.assertEqual( |
|
103 posixpath.commonprefix(["/home/swen/spam", "/home/swen/spam"]), |
|
104 "/home/swen/spam" |
|
105 ) |
|
106 |
|
107 def test_getsize(self): |
|
108 f = open(test_support.TESTFN, "wb") |
|
109 try: |
|
110 f.write("foo") |
|
111 f.close() |
|
112 self.assertEqual(posixpath.getsize(test_support.TESTFN), 3) |
|
113 finally: |
|
114 if not f.closed: |
|
115 f.close() |
|
116 os.remove(test_support.TESTFN) |
|
117 |
|
118 def test_time(self): |
|
119 f = open(test_support.TESTFN, "wb") |
|
120 try: |
|
121 f.write("foo") |
|
122 f.close() |
|
123 f = open(test_support.TESTFN, "ab") |
|
124 f.write("bar") |
|
125 f.close() |
|
126 f = open(test_support.TESTFN, "rb") |
|
127 d = f.read() |
|
128 f.close() |
|
129 self.assertEqual(d, "foobar") |
|
130 |
|
131 self.assert_( |
|
132 posixpath.getctime(test_support.TESTFN) <= |
|
133 posixpath.getmtime(test_support.TESTFN) |
|
134 ) |
|
135 finally: |
|
136 if not f.closed: |
|
137 f.close() |
|
138 os.remove(test_support.TESTFN) |
|
139 |
|
140 def test_islink(self): |
|
141 self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False) |
|
142 f = open(test_support.TESTFN + "1", "wb") |
|
143 try: |
|
144 f.write("foo") |
|
145 f.close() |
|
146 self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False) |
|
147 if hasattr(os, "symlink"): |
|
148 os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2") |
|
149 self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True) |
|
150 os.remove(test_support.TESTFN + "1") |
|
151 self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True) |
|
152 self.assertIs(posixpath.exists(test_support.TESTFN + "2"), False) |
|
153 self.assertIs(posixpath.lexists(test_support.TESTFN + "2"), True) |
|
154 finally: |
|
155 if not f.close(): |
|
156 f.close() |
|
157 try: |
|
158 os.remove(test_support.TESTFN + "1") |
|
159 except os.error: |
|
160 pass |
|
161 try: |
|
162 os.remove(test_support.TESTFN + "2") |
|
163 except os.error: |
|
164 pass |
|
165 |
|
166 self.assertRaises(TypeError, posixpath.islink) |
|
167 |
|
168 def test_exists(self): |
|
169 self.assertIs(posixpath.exists(test_support.TESTFN), False) |
|
170 f = open(test_support.TESTFN, "wb") |
|
171 try: |
|
172 f.write("foo") |
|
173 f.close() |
|
174 self.assertIs(posixpath.exists(test_support.TESTFN), True) |
|
175 self.assertIs(posixpath.lexists(test_support.TESTFN), True) |
|
176 finally: |
|
177 if not f.close(): |
|
178 f.close() |
|
179 try: |
|
180 os.remove(test_support.TESTFN) |
|
181 except os.error: |
|
182 pass |
|
183 |
|
184 self.assertRaises(TypeError, posixpath.exists) |
|
185 |
|
186 def test_isdir(self): |
|
187 self.assertIs(posixpath.isdir(test_support.TESTFN), False) |
|
188 f = open(test_support.TESTFN, "wb") |
|
189 try: |
|
190 f.write("foo") |
|
191 f.close() |
|
192 self.assertIs(posixpath.isdir(test_support.TESTFN), False) |
|
193 os.remove(test_support.TESTFN) |
|
194 os.mkdir(test_support.TESTFN) |
|
195 self.assertIs(posixpath.isdir(test_support.TESTFN), True) |
|
196 os.rmdir(test_support.TESTFN) |
|
197 finally: |
|
198 if not f.close(): |
|
199 f.close() |
|
200 try: |
|
201 os.remove(test_support.TESTFN) |
|
202 except os.error: |
|
203 pass |
|
204 try: |
|
205 os.rmdir(test_support.TESTFN) |
|
206 except os.error: |
|
207 pass |
|
208 |
|
209 self.assertRaises(TypeError, posixpath.isdir) |
|
210 |
|
211 def test_isfile(self): |
|
212 self.assertIs(posixpath.isfile(test_support.TESTFN), False) |
|
213 f = open(test_support.TESTFN, "wb") |
|
214 try: |
|
215 f.write("foo") |
|
216 f.close() |
|
217 self.assertIs(posixpath.isfile(test_support.TESTFN), True) |
|
218 os.remove(test_support.TESTFN) |
|
219 os.mkdir(test_support.TESTFN) |
|
220 self.assertIs(posixpath.isfile(test_support.TESTFN), False) |
|
221 os.rmdir(test_support.TESTFN) |
|
222 finally: |
|
223 if not f.close(): |
|
224 f.close() |
|
225 try: |
|
226 os.remove(test_support.TESTFN) |
|
227 except os.error: |
|
228 pass |
|
229 try: |
|
230 os.rmdir(test_support.TESTFN) |
|
231 except os.error: |
|
232 pass |
|
233 |
|
234 self.assertRaises(TypeError, posixpath.isdir) |
|
235 |
|
236 def test_samefile(self): |
|
237 f = open(test_support.TESTFN + "1", "wb") |
|
238 try: |
|
239 f.write("foo") |
|
240 f.close() |
|
241 self.assertIs( |
|
242 posixpath.samefile( |
|
243 test_support.TESTFN + "1", |
|
244 test_support.TESTFN + "1" |
|
245 ), |
|
246 True |
|
247 ) |
|
248 # If we don't have links, assume that os.stat doesn't return resonable |
|
249 # inode information and thus, that samefile() doesn't work |
|
250 if hasattr(os, "symlink"): |
|
251 os.symlink( |
|
252 test_support.TESTFN + "1", |
|
253 test_support.TESTFN + "2" |
|
254 ) |
|
255 self.assertIs( |
|
256 posixpath.samefile( |
|
257 test_support.TESTFN + "1", |
|
258 test_support.TESTFN + "2" |
|
259 ), |
|
260 True |
|
261 ) |
|
262 os.remove(test_support.TESTFN + "2") |
|
263 f = open(test_support.TESTFN + "2", "wb") |
|
264 f.write("bar") |
|
265 f.close() |
|
266 self.assertIs( |
|
267 posixpath.samefile( |
|
268 test_support.TESTFN + "1", |
|
269 test_support.TESTFN + "2" |
|
270 ), |
|
271 False |
|
272 ) |
|
273 finally: |
|
274 if not f.close(): |
|
275 f.close() |
|
276 try: |
|
277 os.remove(test_support.TESTFN + "1") |
|
278 except os.error: |
|
279 pass |
|
280 try: |
|
281 os.remove(test_support.TESTFN + "2") |
|
282 except os.error: |
|
283 pass |
|
284 |
|
285 self.assertRaises(TypeError, posixpath.samefile) |
|
286 |
|
287 def test_samestat(self): |
|
288 f = open(test_support.TESTFN + "1", "wb") |
|
289 try: |
|
290 f.write("foo") |
|
291 f.close() |
|
292 self.assertIs( |
|
293 posixpath.samestat( |
|
294 os.stat(test_support.TESTFN + "1"), |
|
295 os.stat(test_support.TESTFN + "1") |
|
296 ), |
|
297 True |
|
298 ) |
|
299 # If we don't have links, assume that os.stat() doesn't return resonable |
|
300 # inode information and thus, that samefile() doesn't work |
|
301 if hasattr(os, "symlink"): |
|
302 if hasattr(os, "symlink"): |
|
303 os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2") |
|
304 self.assertIs( |
|
305 posixpath.samestat( |
|
306 os.stat(test_support.TESTFN + "1"), |
|
307 os.stat(test_support.TESTFN + "2") |
|
308 ), |
|
309 True |
|
310 ) |
|
311 os.remove(test_support.TESTFN + "2") |
|
312 f = open(test_support.TESTFN + "2", "wb") |
|
313 f.write("bar") |
|
314 f.close() |
|
315 self.assertIs( |
|
316 posixpath.samestat( |
|
317 os.stat(test_support.TESTFN + "1"), |
|
318 os.stat(test_support.TESTFN + "2") |
|
319 ), |
|
320 False |
|
321 ) |
|
322 finally: |
|
323 if not f.close(): |
|
324 f.close() |
|
325 try: |
|
326 os.remove(test_support.TESTFN + "1") |
|
327 except os.error: |
|
328 pass |
|
329 try: |
|
330 os.remove(test_support.TESTFN + "2") |
|
331 except os.error: |
|
332 pass |
|
333 |
|
334 self.assertRaises(TypeError, posixpath.samestat) |
|
335 |
|
336 def test_ismount(self): |
|
337 self.assertIs(posixpath.ismount("/"), True) |
|
338 |
|
339 self.assertRaises(TypeError, posixpath.ismount) |
|
340 |
|
341 def test_expanduser(self): |
|
342 self.assertEqual(posixpath.expanduser("foo"), "foo") |
|
343 try: |
|
344 import pwd |
|
345 except ImportError: |
|
346 pass |
|
347 else: |
|
348 self.assert_(isinstance(posixpath.expanduser("~/"), basestring)) |
|
349 # if home directory == root directory, this test makes no sense |
|
350 if posixpath.expanduser("~") != '/': |
|
351 self.assertEqual( |
|
352 posixpath.expanduser("~") + "/", |
|
353 posixpath.expanduser("~/") |
|
354 ) |
|
355 self.assert_(isinstance(posixpath.expanduser("~root/"), basestring)) |
|
356 self.assert_(isinstance(posixpath.expanduser("~foo/"), basestring)) |
|
357 |
|
358 self.assertRaises(TypeError, posixpath.expanduser) |
|
359 |
|
360 def test_expandvars(self): |
|
361 oldenv = os.environ.copy() |
|
362 try: |
|
363 os.environ.clear() |
|
364 os.environ["foo"] = "bar" |
|
365 os.environ["{foo"] = "baz1" |
|
366 os.environ["{foo}"] = "baz2" |
|
367 self.assertEqual(posixpath.expandvars("foo"), "foo") |
|
368 self.assertEqual(posixpath.expandvars("$foo bar"), "bar bar") |
|
369 self.assertEqual(posixpath.expandvars("${foo}bar"), "barbar") |
|
370 self.assertEqual(posixpath.expandvars("$[foo]bar"), "$[foo]bar") |
|
371 self.assertEqual(posixpath.expandvars("$bar bar"), "$bar bar") |
|
372 self.assertEqual(posixpath.expandvars("$?bar"), "$?bar") |
|
373 self.assertEqual(posixpath.expandvars("${foo}bar"), "barbar") |
|
374 self.assertEqual(posixpath.expandvars("$foo}bar"), "bar}bar") |
|
375 self.assertEqual(posixpath.expandvars("${foo"), "${foo") |
|
376 self.assertEqual(posixpath.expandvars("${{foo}}"), "baz1}") |
|
377 finally: |
|
378 os.environ.clear() |
|
379 os.environ.update(oldenv) |
|
380 |
|
381 self.assertRaises(TypeError, posixpath.expandvars) |
|
382 |
|
383 def test_normpath(self): |
|
384 self.assertEqual(posixpath.normpath(""), ".") |
|
385 self.assertEqual(posixpath.normpath("/"), "/") |
|
386 self.assertEqual(posixpath.normpath("//"), "//") |
|
387 self.assertEqual(posixpath.normpath("///"), "/") |
|
388 self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar") |
|
389 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), "/foo/baz") |
|
390 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar") |
|
391 |
|
392 self.assertRaises(TypeError, posixpath.normpath) |
|
393 |
|
394 def test_abspath(self): |
|
395 self.assert_("foo" in posixpath.abspath("foo")) |
|
396 |
|
397 self.assertRaises(TypeError, posixpath.abspath) |
|
398 |
|
399 def test_realpath(self): |
|
400 self.assert_("foo" in realpath("foo")) |
|
401 self.assertRaises(TypeError, posixpath.realpath) |
|
402 |
|
403 if hasattr(os, "symlink"): |
|
404 def test_realpath_basic(self): |
|
405 # Basic operation. |
|
406 try: |
|
407 os.symlink(ABSTFN+"1", ABSTFN) |
|
408 self.assertEqual(realpath(ABSTFN), ABSTFN+"1") |
|
409 finally: |
|
410 self.safe_remove(ABSTFN) |
|
411 |
|
412 def test_realpath_symlink_loops(self): |
|
413 # Bug #930024, return the path unchanged if we get into an infinite |
|
414 # symlink loop. |
|
415 try: |
|
416 old_path = abspath('.') |
|
417 os.symlink(ABSTFN, ABSTFN) |
|
418 self.assertEqual(realpath(ABSTFN), ABSTFN) |
|
419 |
|
420 os.symlink(ABSTFN+"1", ABSTFN+"2") |
|
421 os.symlink(ABSTFN+"2", ABSTFN+"1") |
|
422 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1") |
|
423 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2") |
|
424 |
|
425 # Test using relative path as well. |
|
426 os.chdir(dirname(ABSTFN)) |
|
427 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN) |
|
428 finally: |
|
429 os.chdir(old_path) |
|
430 self.safe_remove(ABSTFN) |
|
431 self.safe_remove(ABSTFN+"1") |
|
432 self.safe_remove(ABSTFN+"2") |
|
433 |
|
434 def test_realpath_resolve_parents(self): |
|
435 # We also need to resolve any symlinks in the parents of a relative |
|
436 # path passed to realpath. E.g.: current working directory is |
|
437 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call |
|
438 # realpath("a"). This should return /usr/share/doc/a/. |
|
439 try: |
|
440 old_path = abspath('.') |
|
441 os.mkdir(ABSTFN) |
|
442 os.mkdir(ABSTFN + "/y") |
|
443 os.symlink(ABSTFN + "/y", ABSTFN + "/k") |
|
444 |
|
445 os.chdir(ABSTFN + "/k") |
|
446 self.assertEqual(realpath("a"), ABSTFN + "/y/a") |
|
447 finally: |
|
448 os.chdir(old_path) |
|
449 self.safe_remove(ABSTFN + "/k") |
|
450 self.safe_rmdir(ABSTFN + "/y") |
|
451 self.safe_rmdir(ABSTFN) |
|
452 |
|
453 def test_realpath_resolve_before_normalizing(self): |
|
454 # Bug #990669: Symbolic links should be resolved before we |
|
455 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y' |
|
456 # in the following hierarchy: |
|
457 # a/k/y |
|
458 # |
|
459 # and a symbolic link 'link-y' pointing to 'y' in directory 'a', |
|
460 # then realpath("link-y/..") should return 'k', not 'a'. |
|
461 try: |
|
462 old_path = abspath('.') |
|
463 os.mkdir(ABSTFN) |
|
464 os.mkdir(ABSTFN + "/k") |
|
465 os.mkdir(ABSTFN + "/k/y") |
|
466 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y") |
|
467 |
|
468 # Absolute path. |
|
469 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k") |
|
470 # Relative path. |
|
471 os.chdir(dirname(ABSTFN)) |
|
472 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."), ABSTFN + "/k") |
|
473 finally: |
|
474 os.chdir(old_path) |
|
475 self.safe_remove(ABSTFN + "/link-y") |
|
476 self.safe_rmdir(ABSTFN + "/k/y") |
|
477 self.safe_rmdir(ABSTFN + "/k") |
|
478 self.safe_rmdir(ABSTFN) |
|
479 |
|
480 def test_realpath_resolve_first(self): |
|
481 # Bug #1213894: The first component of the path, if not absolute, |
|
482 # must be resolved too. |
|
483 |
|
484 try: |
|
485 old_path = abspath('.') |
|
486 os.mkdir(ABSTFN) |
|
487 os.mkdir(ABSTFN + "/k") |
|
488 os.symlink(ABSTFN, ABSTFN + "link") |
|
489 os.chdir(dirname(ABSTFN)) |
|
490 |
|
491 base = basename(ABSTFN) |
|
492 self.assertEqual(realpath(base + "link"), ABSTFN) |
|
493 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k") |
|
494 finally: |
|
495 os.chdir(old_path) |
|
496 self.safe_remove(ABSTFN + "link") |
|
497 self.safe_rmdir(ABSTFN + "/k") |
|
498 self.safe_rmdir(ABSTFN) |
|
499 |
|
500 # Convenience functions for removing temporary files. |
|
501 def pass_os_error(self, func, filename): |
|
502 try: func(filename) |
|
503 except OSError: pass |
|
504 |
|
505 def safe_remove(self, filename): |
|
506 self.pass_os_error(os.remove, filename) |
|
507 |
|
508 def safe_rmdir(self, dirname): |
|
509 self.pass_os_error(os.rmdir, dirname) |
|
510 |
|
511 def test_main(): |
|
512 test_support.run_unittest(PosixPathTest) |
|
513 |
|
514 if __name__=="__main__": |
|
515 test_main() |