blob: d2722645954ba90e5d287647483ed85243b28600 [file] [log] [blame]
Antoine Pitrou31119e42013-11-22 17:38:12 +01001import collections
2import io
3import os
4import errno
5import pathlib
6import pickle
7import shutil
8import socket
9import stat
10import sys
11import tempfile
12import unittest
13from contextlib import contextmanager
14
15from test import support
16TESTFN = support.TESTFN
17
18try:
19 import grp, pwd
20except ImportError:
21 grp = pwd = None
22
23
24class _BaseFlavourTest(object):
25
26 def _check_parse_parts(self, arg, expected):
27 f = self.flavour.parse_parts
28 sep = self.flavour.sep
29 altsep = self.flavour.altsep
30 actual = f([x.replace('/', sep) for x in arg])
31 self.assertEqual(actual, expected)
32 if altsep:
33 actual = f([x.replace('/', altsep) for x in arg])
34 self.assertEqual(actual, expected)
35
36 def test_parse_parts_common(self):
37 check = self._check_parse_parts
38 sep = self.flavour.sep
39 # Unanchored parts
40 check([], ('', '', []))
41 check(['a'], ('', '', ['a']))
42 check(['a/'], ('', '', ['a']))
43 check(['a', 'b'], ('', '', ['a', 'b']))
44 # Expansion
45 check(['a/b'], ('', '', ['a', 'b']))
46 check(['a/b/'], ('', '', ['a', 'b']))
47 check(['a', 'b/c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
48 # Collapsing and stripping excess slashes
49 check(['a', 'b//c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
50 check(['a', 'b/c/', 'd'], ('', '', ['a', 'b', 'c', 'd']))
51 # Eliminating standalone dots
52 check(['.'], ('', '', []))
53 check(['.', '.', 'b'], ('', '', ['b']))
54 check(['a', '.', 'b'], ('', '', ['a', 'b']))
55 check(['a', '.', '.'], ('', '', ['a']))
56 # The first part is anchored
57 check(['/a/b'], ('', sep, [sep, 'a', 'b']))
58 check(['/a', 'b'], ('', sep, [sep, 'a', 'b']))
59 check(['/a/', 'b'], ('', sep, [sep, 'a', 'b']))
60 # Ignoring parts before an anchored part
61 check(['a', '/b', 'c'], ('', sep, [sep, 'b', 'c']))
62 check(['a', '/b', '/c'], ('', sep, [sep, 'c']))
63
64
65class PosixFlavourTest(_BaseFlavourTest, unittest.TestCase):
66 flavour = pathlib._posix_flavour
67
68 def test_parse_parts(self):
69 check = self._check_parse_parts
70 # Collapsing of excess leading slashes, except for the double-slash
71 # special case.
72 check(['//a', 'b'], ('', '//', ['//', 'a', 'b']))
73 check(['///a', 'b'], ('', '/', ['/', 'a', 'b']))
74 check(['////a', 'b'], ('', '/', ['/', 'a', 'b']))
75 # Paths which look like NT paths aren't treated specially
76 check(['c:a'], ('', '', ['c:a']))
77 check(['c:\\a'], ('', '', ['c:\\a']))
78 check(['\\a'], ('', '', ['\\a']))
79
80 def test_splitroot(self):
81 f = self.flavour.splitroot
82 self.assertEqual(f(''), ('', '', ''))
83 self.assertEqual(f('a'), ('', '', 'a'))
84 self.assertEqual(f('a/b'), ('', '', 'a/b'))
85 self.assertEqual(f('a/b/'), ('', '', 'a/b/'))
86 self.assertEqual(f('/a'), ('', '/', 'a'))
87 self.assertEqual(f('/a/b'), ('', '/', 'a/b'))
88 self.assertEqual(f('/a/b/'), ('', '/', 'a/b/'))
89 # The root is collapsed when there are redundant slashes
90 # except when there are exactly two leading slashes, which
91 # is a special case in POSIX.
92 self.assertEqual(f('//a'), ('', '//', 'a'))
93 self.assertEqual(f('///a'), ('', '/', 'a'))
94 self.assertEqual(f('///a/b'), ('', '/', 'a/b'))
95 # Paths which look like NT paths aren't treated specially
96 self.assertEqual(f('c:/a/b'), ('', '', 'c:/a/b'))
97 self.assertEqual(f('\\/a/b'), ('', '', '\\/a/b'))
98 self.assertEqual(f('\\a\\b'), ('', '', '\\a\\b'))
99
100
101class NTFlavourTest(_BaseFlavourTest, unittest.TestCase):
102 flavour = pathlib._windows_flavour
103
104 def test_parse_parts(self):
105 check = self._check_parse_parts
106 # First part is anchored
107 check(['c:'], ('c:', '', ['c:']))
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100108 check(['c:/'], ('c:', '\\', ['c:\\']))
109 check(['/'], ('', '\\', ['\\']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100110 check(['c:a'], ('c:', '', ['c:', 'a']))
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100111 check(['c:/a'], ('c:', '\\', ['c:\\', 'a']))
112 check(['/a'], ('', '\\', ['\\', 'a']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100113 # UNC paths
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100114 check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
115 check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
116 check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100117 # Second part is anchored, so that the first part is ignored
118 check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c']))
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100119 check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100120 # UNC paths
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100121 check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100122 # Collapsing and stripping excess slashes
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100123 check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100124 # UNC paths
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100125 check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100126 # Extended paths
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100127 check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\']))
128 check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a']))
129 check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100130 # Extended UNC paths (format is "\\?\UNC\server\share")
Antoine Pitrou57fffd62015-02-15 18:03:59 +0100131 check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\']))
132 check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd']))
133 # Second part has a root but not drive
134 check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c']))
135 check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
136 check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c']))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100137
138 def test_splitroot(self):
139 f = self.flavour.splitroot
140 self.assertEqual(f(''), ('', '', ''))
141 self.assertEqual(f('a'), ('', '', 'a'))
142 self.assertEqual(f('a\\b'), ('', '', 'a\\b'))
143 self.assertEqual(f('\\a'), ('', '\\', 'a'))
144 self.assertEqual(f('\\a\\b'), ('', '\\', 'a\\b'))
145 self.assertEqual(f('c:a\\b'), ('c:', '', 'a\\b'))
146 self.assertEqual(f('c:\\a\\b'), ('c:', '\\', 'a\\b'))
147 # Redundant slashes in the root are collapsed
148 self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
149 self.assertEqual(f('\\\\\\a/b'), ('', '\\', 'a/b'))
150 self.assertEqual(f('c:\\\\a'), ('c:', '\\', 'a'))
151 self.assertEqual(f('c:\\\\\\a/b'), ('c:', '\\', 'a/b'))
152 # Valid UNC paths
153 self.assertEqual(f('\\\\a\\b'), ('\\\\a\\b', '\\', ''))
154 self.assertEqual(f('\\\\a\\b\\'), ('\\\\a\\b', '\\', ''))
155 self.assertEqual(f('\\\\a\\b\\c\\d'), ('\\\\a\\b', '\\', 'c\\d'))
156 # These are non-UNC paths (according to ntpath.py and test_ntpath)
157 # However, command.com says such paths are invalid, so it's
158 # difficult to know what the right semantics are
159 self.assertEqual(f('\\\\\\a\\b'), ('', '\\', 'a\\b'))
160 self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
161
162
163#
164# Tests for the pure classes
165#
166
167class _BasePurePathTest(object):
168
169 # keys are canonical paths, values are list of tuples of arguments
170 # supposed to produce equal paths
171 equivalences = {
172 'a/b': [
173 ('a', 'b'), ('a/', 'b'), ('a', 'b/'), ('a/', 'b/'),
174 ('a/b/',), ('a//b',), ('a//b//',),
175 # empty components get removed
176 ('', 'a', 'b'), ('a', '', 'b'), ('a', 'b', ''),
177 ],
178 '/b/c/d': [
179 ('a', '/b/c', 'd'), ('a', '///b//c', 'd/'),
180 ('/a', '/b/c', 'd'),
181 # empty components get removed
182 ('/', 'b', '', 'c/d'), ('/', '', 'b/c/d'), ('', '/b/c/d'),
183 ],
184 }
185
186 def setUp(self):
187 p = self.cls('a')
188 self.flavour = p._flavour
189 self.sep = self.flavour.sep
190 self.altsep = self.flavour.altsep
191
192 def test_constructor_common(self):
193 P = self.cls
194 p = P('a')
195 self.assertIsInstance(p, P)
196 P('a', 'b', 'c')
197 P('/a', 'b', 'c')
198 P('a/b/c')
199 P('/a/b/c')
200 self.assertEqual(P(P('a')), P('a'))
201 self.assertEqual(P(P('a'), 'b'), P('a/b'))
202 self.assertEqual(P(P('a'), P('b')), P('a/b'))
203
Antoine Pitroucb5ec772014-04-23 00:34:15 +0200204 def _check_str_subclass(self, *args):
205 # Issue #21127: it should be possible to construct a PurePath object
206 # from an str subclass instance, and it then gets converted to
207 # a pure str object.
208 class StrSubclass(str):
209 pass
210 P = self.cls
211 p = P(*(StrSubclass(x) for x in args))
212 self.assertEqual(p, P(*args))
213 for part in p.parts:
214 self.assertIs(type(part), str)
215
216 def test_str_subclass_common(self):
217 self._check_str_subclass('')
218 self._check_str_subclass('.')
219 self._check_str_subclass('a')
220 self._check_str_subclass('a/b.txt')
221 self._check_str_subclass('/a/b.txt')
222
Antoine Pitrou31119e42013-11-22 17:38:12 +0100223 def test_join_common(self):
224 P = self.cls
225 p = P('a/b')
226 pp = p.joinpath('c')
227 self.assertEqual(pp, P('a/b/c'))
228 self.assertIs(type(pp), type(p))
229 pp = p.joinpath('c', 'd')
230 self.assertEqual(pp, P('a/b/c/d'))
231 pp = p.joinpath(P('c'))
232 self.assertEqual(pp, P('a/b/c'))
233 pp = p.joinpath('/c')
234 self.assertEqual(pp, P('/c'))
235
236 def test_div_common(self):
237 # Basically the same as joinpath()
238 P = self.cls
239 p = P('a/b')
240 pp = p / 'c'
241 self.assertEqual(pp, P('a/b/c'))
242 self.assertIs(type(pp), type(p))
243 pp = p / 'c/d'
244 self.assertEqual(pp, P('a/b/c/d'))
245 pp = p / 'c' / 'd'
246 self.assertEqual(pp, P('a/b/c/d'))
247 pp = 'c' / p / 'd'
248 self.assertEqual(pp, P('c/a/b/d'))
249 pp = p / P('c')
250 self.assertEqual(pp, P('a/b/c'))
251 pp = p/ '/c'
252 self.assertEqual(pp, P('/c'))
253
254 def _check_str(self, expected, args):
255 p = self.cls(*args)
256 self.assertEqual(str(p), expected.replace('/', self.sep))
257
258 def test_str_common(self):
259 # Canonicalized paths roundtrip
260 for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
261 self._check_str(pathstr, (pathstr,))
262 # Special case for the empty path
263 self._check_str('.', ('',))
264 # Other tests for str() are in test_equivalences()
265
266 def test_as_posix_common(self):
267 P = self.cls
268 for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
269 self.assertEqual(P(pathstr).as_posix(), pathstr)
270 # Other tests for as_posix() are in test_equivalences()
271
272 def test_as_bytes_common(self):
273 sep = os.fsencode(self.sep)
274 P = self.cls
275 self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b')
276
277 def test_as_uri_common(self):
278 P = self.cls
279 with self.assertRaises(ValueError):
280 P('a').as_uri()
281 with self.assertRaises(ValueError):
282 P().as_uri()
283
284 def test_repr_common(self):
285 for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
286 p = self.cls(pathstr)
287 clsname = p.__class__.__name__
288 r = repr(p)
289 # The repr() is in the form ClassName("forward-slashes path")
290 self.assertTrue(r.startswith(clsname + '('), r)
291 self.assertTrue(r.endswith(')'), r)
292 inner = r[len(clsname) + 1 : -1]
293 self.assertEqual(eval(inner), p.as_posix())
294 # The repr() roundtrips
295 q = eval(r, pathlib.__dict__)
296 self.assertIs(q.__class__, p.__class__)
297 self.assertEqual(q, p)
298 self.assertEqual(repr(q), r)
299
300 def test_eq_common(self):
301 P = self.cls
302 self.assertEqual(P('a/b'), P('a/b'))
303 self.assertEqual(P('a/b'), P('a', 'b'))
304 self.assertNotEqual(P('a/b'), P('a'))
305 self.assertNotEqual(P('a/b'), P('/a/b'))
306 self.assertNotEqual(P('a/b'), P())
307 self.assertNotEqual(P('/a/b'), P('/'))
308 self.assertNotEqual(P(), P('/'))
309 self.assertNotEqual(P(), "")
310 self.assertNotEqual(P(), {})
311 self.assertNotEqual(P(), int)
312
313 def test_match_common(self):
314 P = self.cls
315 self.assertRaises(ValueError, P('a').match, '')
316 self.assertRaises(ValueError, P('a').match, '.')
317 # Simple relative pattern
318 self.assertTrue(P('b.py').match('b.py'))
319 self.assertTrue(P('a/b.py').match('b.py'))
320 self.assertTrue(P('/a/b.py').match('b.py'))
321 self.assertFalse(P('a.py').match('b.py'))
322 self.assertFalse(P('b/py').match('b.py'))
323 self.assertFalse(P('/a.py').match('b.py'))
324 self.assertFalse(P('b.py/c').match('b.py'))
325 # Wilcard relative pattern
326 self.assertTrue(P('b.py').match('*.py'))
327 self.assertTrue(P('a/b.py').match('*.py'))
328 self.assertTrue(P('/a/b.py').match('*.py'))
329 self.assertFalse(P('b.pyc').match('*.py'))
330 self.assertFalse(P('b./py').match('*.py'))
331 self.assertFalse(P('b.py/c').match('*.py'))
332 # Multi-part relative pattern
333 self.assertTrue(P('ab/c.py').match('a*/*.py'))
334 self.assertTrue(P('/d/ab/c.py').match('a*/*.py'))
335 self.assertFalse(P('a.py').match('a*/*.py'))
336 self.assertFalse(P('/dab/c.py').match('a*/*.py'))
337 self.assertFalse(P('ab/c.py/d').match('a*/*.py'))
338 # Absolute pattern
339 self.assertTrue(P('/b.py').match('/*.py'))
340 self.assertFalse(P('b.py').match('/*.py'))
341 self.assertFalse(P('a/b.py').match('/*.py'))
342 self.assertFalse(P('/a/b.py').match('/*.py'))
343 # Multi-part absolute pattern
344 self.assertTrue(P('/a/b.py').match('/a/*.py'))
345 self.assertFalse(P('/ab.py').match('/a/*.py'))
346 self.assertFalse(P('/a/b/c.py').match('/a/*.py'))
347
348 def test_ordering_common(self):
349 # Ordering is tuple-alike
350 def assertLess(a, b):
351 self.assertLess(a, b)
352 self.assertGreater(b, a)
353 P = self.cls
354 a = P('a')
355 b = P('a/b')
356 c = P('abc')
357 d = P('b')
358 assertLess(a, b)
359 assertLess(a, c)
360 assertLess(a, d)
361 assertLess(b, c)
362 assertLess(c, d)
363 P = self.cls
364 a = P('/a')
365 b = P('/a/b')
366 c = P('/abc')
367 d = P('/b')
368 assertLess(a, b)
369 assertLess(a, c)
370 assertLess(a, d)
371 assertLess(b, c)
372 assertLess(c, d)
373 with self.assertRaises(TypeError):
374 P() < {}
375
376 def test_parts_common(self):
377 # `parts` returns a tuple
378 sep = self.sep
379 P = self.cls
380 p = P('a/b')
381 parts = p.parts
382 self.assertEqual(parts, ('a', 'b'))
383 # The object gets reused
384 self.assertIs(parts, p.parts)
385 # When the path is absolute, the anchor is a separate part
386 p = P('/a/b')
387 parts = p.parts
388 self.assertEqual(parts, (sep, 'a', 'b'))
389
390 def test_equivalences(self):
391 for k, tuples in self.equivalences.items():
392 canon = k.replace('/', self.sep)
393 posix = k.replace(self.sep, '/')
394 if canon != posix:
395 tuples = tuples + [
396 tuple(part.replace('/', self.sep) for part in t)
397 for t in tuples
398 ]
399 tuples.append((posix, ))
400 pcanon = self.cls(canon)
401 for t in tuples:
402 p = self.cls(*t)
403 self.assertEqual(p, pcanon, "failed with args {}".format(t))
404 self.assertEqual(hash(p), hash(pcanon))
405 self.assertEqual(str(p), canon)
406 self.assertEqual(p.as_posix(), posix)
407
408 def test_parent_common(self):
409 # Relative
410 P = self.cls
411 p = P('a/b/c')
412 self.assertEqual(p.parent, P('a/b'))
413 self.assertEqual(p.parent.parent, P('a'))
414 self.assertEqual(p.parent.parent.parent, P())
415 self.assertEqual(p.parent.parent.parent.parent, P())
416 # Anchored
417 p = P('/a/b/c')
418 self.assertEqual(p.parent, P('/a/b'))
419 self.assertEqual(p.parent.parent, P('/a'))
420 self.assertEqual(p.parent.parent.parent, P('/'))
421 self.assertEqual(p.parent.parent.parent.parent, P('/'))
422
423 def test_parents_common(self):
424 # Relative
425 P = self.cls
426 p = P('a/b/c')
427 par = p.parents
428 self.assertEqual(len(par), 3)
429 self.assertEqual(par[0], P('a/b'))
430 self.assertEqual(par[1], P('a'))
431 self.assertEqual(par[2], P('.'))
432 self.assertEqual(list(par), [P('a/b'), P('a'), P('.')])
433 with self.assertRaises(IndexError):
434 par[-1]
435 with self.assertRaises(IndexError):
436 par[3]
437 with self.assertRaises(TypeError):
438 par[0] = p
439 # Anchored
440 p = P('/a/b/c')
441 par = p.parents
442 self.assertEqual(len(par), 3)
443 self.assertEqual(par[0], P('/a/b'))
444 self.assertEqual(par[1], P('/a'))
445 self.assertEqual(par[2], P('/'))
446 self.assertEqual(list(par), [P('/a/b'), P('/a'), P('/')])
447 with self.assertRaises(IndexError):
448 par[3]
449
450 def test_drive_common(self):
451 P = self.cls
452 self.assertEqual(P('a/b').drive, '')
453 self.assertEqual(P('/a/b').drive, '')
454 self.assertEqual(P('').drive, '')
455
456 def test_root_common(self):
457 P = self.cls
458 sep = self.sep
459 self.assertEqual(P('').root, '')
460 self.assertEqual(P('a/b').root, '')
461 self.assertEqual(P('/').root, sep)
462 self.assertEqual(P('/a/b').root, sep)
463
464 def test_anchor_common(self):
465 P = self.cls
466 sep = self.sep
467 self.assertEqual(P('').anchor, '')
468 self.assertEqual(P('a/b').anchor, '')
469 self.assertEqual(P('/').anchor, sep)
470 self.assertEqual(P('/a/b').anchor, sep)
471
472 def test_name_common(self):
473 P = self.cls
474 self.assertEqual(P('').name, '')
475 self.assertEqual(P('.').name, '')
476 self.assertEqual(P('/').name, '')
477 self.assertEqual(P('a/b').name, 'b')
478 self.assertEqual(P('/a/b').name, 'b')
479 self.assertEqual(P('/a/b/.').name, 'b')
480 self.assertEqual(P('a/b.py').name, 'b.py')
481 self.assertEqual(P('/a/b.py').name, 'b.py')
482
483 def test_suffix_common(self):
484 P = self.cls
485 self.assertEqual(P('').suffix, '')
486 self.assertEqual(P('.').suffix, '')
487 self.assertEqual(P('..').suffix, '')
488 self.assertEqual(P('/').suffix, '')
489 self.assertEqual(P('a/b').suffix, '')
490 self.assertEqual(P('/a/b').suffix, '')
491 self.assertEqual(P('/a/b/.').suffix, '')
492 self.assertEqual(P('a/b.py').suffix, '.py')
493 self.assertEqual(P('/a/b.py').suffix, '.py')
494 self.assertEqual(P('a/.hgrc').suffix, '')
495 self.assertEqual(P('/a/.hgrc').suffix, '')
496 self.assertEqual(P('a/.hg.rc').suffix, '.rc')
497 self.assertEqual(P('/a/.hg.rc').suffix, '.rc')
498 self.assertEqual(P('a/b.tar.gz').suffix, '.gz')
499 self.assertEqual(P('/a/b.tar.gz').suffix, '.gz')
500 self.assertEqual(P('a/Some name. Ending with a dot.').suffix, '')
501 self.assertEqual(P('/a/Some name. Ending with a dot.').suffix, '')
502
503 def test_suffixes_common(self):
504 P = self.cls
505 self.assertEqual(P('').suffixes, [])
506 self.assertEqual(P('.').suffixes, [])
507 self.assertEqual(P('/').suffixes, [])
508 self.assertEqual(P('a/b').suffixes, [])
509 self.assertEqual(P('/a/b').suffixes, [])
510 self.assertEqual(P('/a/b/.').suffixes, [])
511 self.assertEqual(P('a/b.py').suffixes, ['.py'])
512 self.assertEqual(P('/a/b.py').suffixes, ['.py'])
513 self.assertEqual(P('a/.hgrc').suffixes, [])
514 self.assertEqual(P('/a/.hgrc').suffixes, [])
515 self.assertEqual(P('a/.hg.rc').suffixes, ['.rc'])
516 self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc'])
517 self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz'])
518 self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz'])
519 self.assertEqual(P('a/Some name. Ending with a dot.').suffixes, [])
520 self.assertEqual(P('/a/Some name. Ending with a dot.').suffixes, [])
521
522 def test_stem_common(self):
523 P = self.cls
524 self.assertEqual(P('').stem, '')
525 self.assertEqual(P('.').stem, '')
526 self.assertEqual(P('..').stem, '..')
527 self.assertEqual(P('/').stem, '')
528 self.assertEqual(P('a/b').stem, 'b')
529 self.assertEqual(P('a/b.py').stem, 'b')
530 self.assertEqual(P('a/.hgrc').stem, '.hgrc')
531 self.assertEqual(P('a/.hg.rc').stem, '.hg')
532 self.assertEqual(P('a/b.tar.gz').stem, 'b.tar')
533 self.assertEqual(P('a/Some name. Ending with a dot.').stem,
534 'Some name. Ending with a dot.')
535
536 def test_with_name_common(self):
537 P = self.cls
538 self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml'))
539 self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml'))
540 self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml'))
541 self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml'))
542 self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml'))
543 self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml'))
544 self.assertRaises(ValueError, P('').with_name, 'd.xml')
545 self.assertRaises(ValueError, P('.').with_name, 'd.xml')
546 self.assertRaises(ValueError, P('/').with_name, 'd.xml')
Antoine Pitrou7084e732014-07-06 21:31:12 -0400547 self.assertRaises(ValueError, P('a/b').with_name, '')
548 self.assertRaises(ValueError, P('a/b').with_name, '/c')
549 self.assertRaises(ValueError, P('a/b').with_name, 'c/')
550 self.assertRaises(ValueError, P('a/b').with_name, 'c/d')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100551
552 def test_with_suffix_common(self):
553 P = self.cls
554 self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz'))
555 self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz'))
556 self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz'))
557 self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz'))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400558 # Stripping suffix
559 self.assertEqual(P('a/b.py').with_suffix(''), P('a/b'))
560 self.assertEqual(P('/a/b').with_suffix(''), P('/a/b'))
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100561 # Path doesn't have a "filename" component
Antoine Pitrou31119e42013-11-22 17:38:12 +0100562 self.assertRaises(ValueError, P('').with_suffix, '.gz')
563 self.assertRaises(ValueError, P('.').with_suffix, '.gz')
564 self.assertRaises(ValueError, P('/').with_suffix, '.gz')
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100565 # Invalid suffix
566 self.assertRaises(ValueError, P('a/b').with_suffix, 'gz')
567 self.assertRaises(ValueError, P('a/b').with_suffix, '/')
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400568 self.assertRaises(ValueError, P('a/b').with_suffix, '.')
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100569 self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz')
570 self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d')
571 self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400572 self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
573 self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100574
575 def test_relative_to_common(self):
576 P = self.cls
577 p = P('a/b')
578 self.assertRaises(TypeError, p.relative_to)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100579 self.assertRaises(TypeError, p.relative_to, b'a')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100580 self.assertEqual(p.relative_to(P()), P('a/b'))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100581 self.assertEqual(p.relative_to(''), P('a/b'))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100582 self.assertEqual(p.relative_to(P('a')), P('b'))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100583 self.assertEqual(p.relative_to('a'), P('b'))
584 self.assertEqual(p.relative_to('a/'), P('b'))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100585 self.assertEqual(p.relative_to(P('a/b')), P())
Antoine Pitrou156b3612013-12-28 19:49:04 +0100586 self.assertEqual(p.relative_to('a/b'), P())
Antoine Pitrou31119e42013-11-22 17:38:12 +0100587 # With several args
588 self.assertEqual(p.relative_to('a', 'b'), P())
589 # Unrelated paths
590 self.assertRaises(ValueError, p.relative_to, P('c'))
591 self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
592 self.assertRaises(ValueError, p.relative_to, P('a/c'))
593 self.assertRaises(ValueError, p.relative_to, P('/a'))
594 p = P('/a/b')
595 self.assertEqual(p.relative_to(P('/')), P('a/b'))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100596 self.assertEqual(p.relative_to('/'), P('a/b'))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100597 self.assertEqual(p.relative_to(P('/a')), P('b'))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100598 self.assertEqual(p.relative_to('/a'), P('b'))
599 self.assertEqual(p.relative_to('/a/'), P('b'))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100600 self.assertEqual(p.relative_to(P('/a/b')), P())
Antoine Pitrou156b3612013-12-28 19:49:04 +0100601 self.assertEqual(p.relative_to('/a/b'), P())
Antoine Pitrou31119e42013-11-22 17:38:12 +0100602 # Unrelated paths
603 self.assertRaises(ValueError, p.relative_to, P('/c'))
604 self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
605 self.assertRaises(ValueError, p.relative_to, P('/a/c'))
606 self.assertRaises(ValueError, p.relative_to, P())
Antoine Pitrou156b3612013-12-28 19:49:04 +0100607 self.assertRaises(ValueError, p.relative_to, '')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100608 self.assertRaises(ValueError, p.relative_to, P('a'))
609
610 def test_pickling_common(self):
611 P = self.cls
612 p = P('/a/b')
613 for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
614 dumped = pickle.dumps(p, proto)
615 pp = pickle.loads(dumped)
616 self.assertIs(pp.__class__, p.__class__)
617 self.assertEqual(pp, p)
618 self.assertEqual(hash(pp), hash(p))
619 self.assertEqual(str(pp), str(p))
620
621
622class PurePosixPathTest(_BasePurePathTest, unittest.TestCase):
623 cls = pathlib.PurePosixPath
624
625 def test_root(self):
626 P = self.cls
627 self.assertEqual(P('/a/b').root, '/')
628 self.assertEqual(P('///a/b').root, '/')
629 # POSIX special case for two leading slashes
630 self.assertEqual(P('//a/b').root, '//')
631
632 def test_eq(self):
633 P = self.cls
634 self.assertNotEqual(P('a/b'), P('A/b'))
635 self.assertEqual(P('/a'), P('///a'))
636 self.assertNotEqual(P('/a'), P('//a'))
637
638 def test_as_uri(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100639 P = self.cls
640 self.assertEqual(P('/').as_uri(), 'file:///')
641 self.assertEqual(P('/a/b.c').as_uri(), 'file:///a/b.c')
642 self.assertEqual(P('/a/b%#c').as_uri(), 'file:///a/b%25%23c')
Antoine Pitrou29eac422013-11-22 17:57:03 +0100643
644 def test_as_uri_non_ascii(self):
645 from urllib.parse import quote_from_bytes
646 P = self.cls
647 try:
648 os.fsencode('\xe9')
649 except UnicodeEncodeError:
650 self.skipTest("\\xe9 cannot be encoded to the filesystem encoding")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100651 self.assertEqual(P('/a/b\xe9').as_uri(),
652 'file:///a/b' + quote_from_bytes(os.fsencode('\xe9')))
653
654 def test_match(self):
655 P = self.cls
656 self.assertFalse(P('A.py').match('a.PY'))
657
658 def test_is_absolute(self):
659 P = self.cls
660 self.assertFalse(P().is_absolute())
661 self.assertFalse(P('a').is_absolute())
662 self.assertFalse(P('a/b/').is_absolute())
663 self.assertTrue(P('/').is_absolute())
664 self.assertTrue(P('/a').is_absolute())
665 self.assertTrue(P('/a/b/').is_absolute())
666 self.assertTrue(P('//a').is_absolute())
667 self.assertTrue(P('//a/b').is_absolute())
668
669 def test_is_reserved(self):
670 P = self.cls
671 self.assertIs(False, P('').is_reserved())
672 self.assertIs(False, P('/').is_reserved())
673 self.assertIs(False, P('/foo/bar').is_reserved())
674 self.assertIs(False, P('/dev/con/PRN/NUL').is_reserved())
675
676 def test_join(self):
677 P = self.cls
678 p = P('//a')
679 pp = p.joinpath('b')
680 self.assertEqual(pp, P('//a/b'))
681 pp = P('/a').joinpath('//c')
682 self.assertEqual(pp, P('//c'))
683 pp = P('//a').joinpath('/c')
684 self.assertEqual(pp, P('/c'))
685
686 def test_div(self):
687 # Basically the same as joinpath()
688 P = self.cls
689 p = P('//a')
690 pp = p / 'b'
691 self.assertEqual(pp, P('//a/b'))
692 pp = P('/a') / '//c'
693 self.assertEqual(pp, P('//c'))
694 pp = P('//a') / '/c'
695 self.assertEqual(pp, P('/c'))
696
697
698class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
699 cls = pathlib.PureWindowsPath
700
701 equivalences = _BasePurePathTest.equivalences.copy()
702 equivalences.update({
703 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('/', 'c:', 'a') ],
704 'c:/a': [
705 ('c:/', 'a'), ('c:', '/', 'a'), ('c:', '/a'),
706 ('/z', 'c:/', 'a'), ('//x/y', 'c:/', 'a'),
707 ],
708 '//a/b/': [ ('//a/b',) ],
709 '//a/b/c': [
710 ('//a/b', 'c'), ('//a/b/', 'c'),
711 ],
712 })
713
714 def test_str(self):
715 p = self.cls('a/b/c')
716 self.assertEqual(str(p), 'a\\b\\c')
717 p = self.cls('c:/a/b/c')
718 self.assertEqual(str(p), 'c:\\a\\b\\c')
719 p = self.cls('//a/b')
720 self.assertEqual(str(p), '\\\\a\\b\\')
721 p = self.cls('//a/b/c')
722 self.assertEqual(str(p), '\\\\a\\b\\c')
723 p = self.cls('//a/b/c/d')
724 self.assertEqual(str(p), '\\\\a\\b\\c\\d')
725
Antoine Pitroucb5ec772014-04-23 00:34:15 +0200726 def test_str_subclass(self):
727 self._check_str_subclass('c:')
728 self._check_str_subclass('c:a')
729 self._check_str_subclass('c:a\\b.txt')
730 self._check_str_subclass('c:\\')
731 self._check_str_subclass('c:\\a')
732 self._check_str_subclass('c:\\a\\b.txt')
733 self._check_str_subclass('\\\\some\\share')
734 self._check_str_subclass('\\\\some\\share\\a')
735 self._check_str_subclass('\\\\some\\share\\a\\b.txt')
736
Antoine Pitrou31119e42013-11-22 17:38:12 +0100737 def test_eq(self):
738 P = self.cls
739 self.assertEqual(P('c:a/b'), P('c:a/b'))
740 self.assertEqual(P('c:a/b'), P('c:', 'a', 'b'))
741 self.assertNotEqual(P('c:a/b'), P('d:a/b'))
742 self.assertNotEqual(P('c:a/b'), P('c:/a/b'))
743 self.assertNotEqual(P('/a/b'), P('c:/a/b'))
744 # Case-insensitivity
745 self.assertEqual(P('a/B'), P('A/b'))
746 self.assertEqual(P('C:a/B'), P('c:A/b'))
747 self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b'))
748
749 def test_as_uri(self):
750 from urllib.parse import quote_from_bytes
751 P = self.cls
752 with self.assertRaises(ValueError):
753 P('/a/b').as_uri()
754 with self.assertRaises(ValueError):
755 P('c:a/b').as_uri()
756 self.assertEqual(P('c:/').as_uri(), 'file:///c:/')
757 self.assertEqual(P('c:/a/b.c').as_uri(), 'file:///c:/a/b.c')
758 self.assertEqual(P('c:/a/b%#c').as_uri(), 'file:///c:/a/b%25%23c')
759 self.assertEqual(P('c:/a/b\xe9').as_uri(), 'file:///c:/a/b%C3%A9')
760 self.assertEqual(P('//some/share/').as_uri(), 'file://some/share/')
761 self.assertEqual(P('//some/share/a/b.c').as_uri(),
762 'file://some/share/a/b.c')
763 self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(),
764 'file://some/share/a/b%25%23c%C3%A9')
765
766 def test_match_common(self):
767 P = self.cls
768 # Absolute patterns
769 self.assertTrue(P('c:/b.py').match('/*.py'))
770 self.assertTrue(P('c:/b.py').match('c:*.py'))
771 self.assertTrue(P('c:/b.py').match('c:/*.py'))
772 self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive
773 self.assertFalse(P('b.py').match('/*.py'))
774 self.assertFalse(P('b.py').match('c:*.py'))
775 self.assertFalse(P('b.py').match('c:/*.py'))
776 self.assertFalse(P('c:b.py').match('/*.py'))
777 self.assertFalse(P('c:b.py').match('c:/*.py'))
778 self.assertFalse(P('/b.py').match('c:*.py'))
779 self.assertFalse(P('/b.py').match('c:/*.py'))
780 # UNC patterns
781 self.assertTrue(P('//some/share/a.py').match('/*.py'))
782 self.assertTrue(P('//some/share/a.py').match('//some/share/*.py'))
783 self.assertFalse(P('//other/share/a.py').match('//some/share/*.py'))
784 self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py'))
785 # Case-insensitivity
786 self.assertTrue(P('B.py').match('b.PY'))
787 self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY'))
788 self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY'))
789
790 def test_ordering_common(self):
791 # Case-insensitivity
792 def assertOrderedEqual(a, b):
793 self.assertLessEqual(a, b)
794 self.assertGreaterEqual(b, a)
795 P = self.cls
796 p = P('c:A/b')
797 q = P('C:a/B')
798 assertOrderedEqual(p, q)
799 self.assertFalse(p < q)
800 self.assertFalse(p > q)
801 p = P('//some/Share/A/b')
802 q = P('//Some/SHARE/a/B')
803 assertOrderedEqual(p, q)
804 self.assertFalse(p < q)
805 self.assertFalse(p > q)
806
807 def test_parts(self):
808 P = self.cls
809 p = P('c:a/b')
810 parts = p.parts
811 self.assertEqual(parts, ('c:', 'a', 'b'))
812 p = P('c:/a/b')
813 parts = p.parts
814 self.assertEqual(parts, ('c:\\', 'a', 'b'))
815 p = P('//a/b/c/d')
816 parts = p.parts
817 self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
818
819 def test_parent(self):
820 # Anchored
821 P = self.cls
822 p = P('z:a/b/c')
823 self.assertEqual(p.parent, P('z:a/b'))
824 self.assertEqual(p.parent.parent, P('z:a'))
825 self.assertEqual(p.parent.parent.parent, P('z:'))
826 self.assertEqual(p.parent.parent.parent.parent, P('z:'))
827 p = P('z:/a/b/c')
828 self.assertEqual(p.parent, P('z:/a/b'))
829 self.assertEqual(p.parent.parent, P('z:/a'))
830 self.assertEqual(p.parent.parent.parent, P('z:/'))
831 self.assertEqual(p.parent.parent.parent.parent, P('z:/'))
832 p = P('//a/b/c/d')
833 self.assertEqual(p.parent, P('//a/b/c'))
834 self.assertEqual(p.parent.parent, P('//a/b'))
835 self.assertEqual(p.parent.parent.parent, P('//a/b'))
836
837 def test_parents(self):
838 # Anchored
839 P = self.cls
840 p = P('z:a/b/')
841 par = p.parents
842 self.assertEqual(len(par), 2)
843 self.assertEqual(par[0], P('z:a'))
844 self.assertEqual(par[1], P('z:'))
845 self.assertEqual(list(par), [P('z:a'), P('z:')])
846 with self.assertRaises(IndexError):
847 par[2]
848 p = P('z:/a/b/')
849 par = p.parents
850 self.assertEqual(len(par), 2)
851 self.assertEqual(par[0], P('z:/a'))
852 self.assertEqual(par[1], P('z:/'))
853 self.assertEqual(list(par), [P('z:/a'), P('z:/')])
854 with self.assertRaises(IndexError):
855 par[2]
856 p = P('//a/b/c/d')
857 par = p.parents
858 self.assertEqual(len(par), 2)
859 self.assertEqual(par[0], P('//a/b/c'))
860 self.assertEqual(par[1], P('//a/b'))
861 self.assertEqual(list(par), [P('//a/b/c'), P('//a/b')])
862 with self.assertRaises(IndexError):
863 par[2]
864
865 def test_drive(self):
866 P = self.cls
867 self.assertEqual(P('c:').drive, 'c:')
868 self.assertEqual(P('c:a/b').drive, 'c:')
869 self.assertEqual(P('c:/').drive, 'c:')
870 self.assertEqual(P('c:/a/b/').drive, 'c:')
871 self.assertEqual(P('//a/b').drive, '\\\\a\\b')
872 self.assertEqual(P('//a/b/').drive, '\\\\a\\b')
873 self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b')
874
875 def test_root(self):
876 P = self.cls
877 self.assertEqual(P('c:').root, '')
878 self.assertEqual(P('c:a/b').root, '')
879 self.assertEqual(P('c:/').root, '\\')
880 self.assertEqual(P('c:/a/b/').root, '\\')
881 self.assertEqual(P('//a/b').root, '\\')
882 self.assertEqual(P('//a/b/').root, '\\')
883 self.assertEqual(P('//a/b/c/d').root, '\\')
884
885 def test_anchor(self):
886 P = self.cls
887 self.assertEqual(P('c:').anchor, 'c:')
888 self.assertEqual(P('c:a/b').anchor, 'c:')
889 self.assertEqual(P('c:/').anchor, 'c:\\')
890 self.assertEqual(P('c:/a/b/').anchor, 'c:\\')
891 self.assertEqual(P('//a/b').anchor, '\\\\a\\b\\')
892 self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\')
893 self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\')
894
895 def test_name(self):
896 P = self.cls
897 self.assertEqual(P('c:').name, '')
898 self.assertEqual(P('c:/').name, '')
899 self.assertEqual(P('c:a/b').name, 'b')
900 self.assertEqual(P('c:/a/b').name, 'b')
901 self.assertEqual(P('c:a/b.py').name, 'b.py')
902 self.assertEqual(P('c:/a/b.py').name, 'b.py')
903 self.assertEqual(P('//My.py/Share.php').name, '')
904 self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
905
906 def test_suffix(self):
907 P = self.cls
908 self.assertEqual(P('c:').suffix, '')
909 self.assertEqual(P('c:/').suffix, '')
910 self.assertEqual(P('c:a/b').suffix, '')
911 self.assertEqual(P('c:/a/b').suffix, '')
912 self.assertEqual(P('c:a/b.py').suffix, '.py')
913 self.assertEqual(P('c:/a/b.py').suffix, '.py')
914 self.assertEqual(P('c:a/.hgrc').suffix, '')
915 self.assertEqual(P('c:/a/.hgrc').suffix, '')
916 self.assertEqual(P('c:a/.hg.rc').suffix, '.rc')
917 self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc')
918 self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz')
919 self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz')
920 self.assertEqual(P('c:a/Some name. Ending with a dot.').suffix, '')
921 self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffix, '')
922 self.assertEqual(P('//My.py/Share.php').suffix, '')
923 self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
924
925 def test_suffixes(self):
926 P = self.cls
927 self.assertEqual(P('c:').suffixes, [])
928 self.assertEqual(P('c:/').suffixes, [])
929 self.assertEqual(P('c:a/b').suffixes, [])
930 self.assertEqual(P('c:/a/b').suffixes, [])
931 self.assertEqual(P('c:a/b.py').suffixes, ['.py'])
932 self.assertEqual(P('c:/a/b.py').suffixes, ['.py'])
933 self.assertEqual(P('c:a/.hgrc').suffixes, [])
934 self.assertEqual(P('c:/a/.hgrc').suffixes, [])
935 self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc'])
936 self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc'])
937 self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz'])
938 self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz'])
939 self.assertEqual(P('//My.py/Share.php').suffixes, [])
940 self.assertEqual(P('//My.py/Share.php/a/b').suffixes, [])
941 self.assertEqual(P('c:a/Some name. Ending with a dot.').suffixes, [])
942 self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffixes, [])
943
944 def test_stem(self):
945 P = self.cls
946 self.assertEqual(P('c:').stem, '')
947 self.assertEqual(P('c:.').stem, '')
948 self.assertEqual(P('c:..').stem, '..')
949 self.assertEqual(P('c:/').stem, '')
950 self.assertEqual(P('c:a/b').stem, 'b')
951 self.assertEqual(P('c:a/b.py').stem, 'b')
952 self.assertEqual(P('c:a/.hgrc').stem, '.hgrc')
953 self.assertEqual(P('c:a/.hg.rc').stem, '.hg')
954 self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
955 self.assertEqual(P('c:a/Some name. Ending with a dot.').stem,
956 'Some name. Ending with a dot.')
957
958 def test_with_name(self):
959 P = self.cls
960 self.assertEqual(P('c:a/b').with_name('d.xml'), P('c:a/d.xml'))
961 self.assertEqual(P('c:/a/b').with_name('d.xml'), P('c:/a/d.xml'))
962 self.assertEqual(P('c:a/Dot ending.').with_name('d.xml'), P('c:a/d.xml'))
963 self.assertEqual(P('c:/a/Dot ending.').with_name('d.xml'), P('c:/a/d.xml'))
964 self.assertRaises(ValueError, P('c:').with_name, 'd.xml')
965 self.assertRaises(ValueError, P('c:/').with_name, 'd.xml')
966 self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml')
Antoine Pitrou7084e732014-07-06 21:31:12 -0400967 self.assertRaises(ValueError, P('c:a/b').with_name, 'd:')
968 self.assertRaises(ValueError, P('c:a/b').with_name, 'd:e')
969 self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e')
970 self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100971
972 def test_with_suffix(self):
973 P = self.cls
974 self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz'))
975 self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz'))
976 self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz'))
977 self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz'))
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100978 # Path doesn't have a "filename" component
Antoine Pitrou31119e42013-11-22 17:38:12 +0100979 self.assertRaises(ValueError, P('').with_suffix, '.gz')
980 self.assertRaises(ValueError, P('.').with_suffix, '.gz')
981 self.assertRaises(ValueError, P('/').with_suffix, '.gz')
982 self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz')
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100983 # Invalid suffix
984 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz')
985 self.assertRaises(ValueError, P('c:a/b').with_suffix, '/')
986 self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\')
987 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:')
988 self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz')
989 self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz')
990 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz')
991 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d')
992 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d')
993 self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d')
994 self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100995
996 def test_relative_to(self):
997 P = self.cls
Antoine Pitrou156b3612013-12-28 19:49:04 +0100998 p = P('C:Foo/Bar')
999 self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar'))
1000 self.assertEqual(p.relative_to('c:'), P('Foo/Bar'))
1001 self.assertEqual(p.relative_to(P('c:foO')), P('Bar'))
1002 self.assertEqual(p.relative_to('c:foO'), P('Bar'))
1003 self.assertEqual(p.relative_to('c:foO/'), P('Bar'))
1004 self.assertEqual(p.relative_to(P('c:foO/baR')), P())
1005 self.assertEqual(p.relative_to('c:foO/baR'), P())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001006 # Unrelated paths
1007 self.assertRaises(ValueError, p.relative_to, P())
Antoine Pitrou156b3612013-12-28 19:49:04 +01001008 self.assertRaises(ValueError, p.relative_to, '')
Antoine Pitrou31119e42013-11-22 17:38:12 +01001009 self.assertRaises(ValueError, p.relative_to, P('d:'))
Antoine Pitrou156b3612013-12-28 19:49:04 +01001010 self.assertRaises(ValueError, p.relative_to, P('/'))
1011 self.assertRaises(ValueError, p.relative_to, P('Foo'))
1012 self.assertRaises(ValueError, p.relative_to, P('/Foo'))
1013 self.assertRaises(ValueError, p.relative_to, P('C:/Foo'))
1014 self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz'))
1015 self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz'))
1016 p = P('C:/Foo/Bar')
1017 self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar'))
1018 self.assertEqual(p.relative_to('c:'), P('/Foo/Bar'))
1019 self.assertEqual(str(p.relative_to(P('c:'))), '\\Foo\\Bar')
1020 self.assertEqual(str(p.relative_to('c:')), '\\Foo\\Bar')
1021 self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar'))
1022 self.assertEqual(p.relative_to('c:/'), P('Foo/Bar'))
1023 self.assertEqual(p.relative_to(P('c:/foO')), P('Bar'))
1024 self.assertEqual(p.relative_to('c:/foO'), P('Bar'))
1025 self.assertEqual(p.relative_to('c:/foO/'), P('Bar'))
1026 self.assertEqual(p.relative_to(P('c:/foO/baR')), P())
1027 self.assertEqual(p.relative_to('c:/foO/baR'), P())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001028 # Unrelated paths
Antoine Pitrou156b3612013-12-28 19:49:04 +01001029 self.assertRaises(ValueError, p.relative_to, P('C:/Baz'))
1030 self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz'))
1031 self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz'))
1032 self.assertRaises(ValueError, p.relative_to, P('C:Foo'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001033 self.assertRaises(ValueError, p.relative_to, P('d:'))
1034 self.assertRaises(ValueError, p.relative_to, P('d:/'))
Antoine Pitrou156b3612013-12-28 19:49:04 +01001035 self.assertRaises(ValueError, p.relative_to, P('/'))
1036 self.assertRaises(ValueError, p.relative_to, P('/Foo'))
1037 self.assertRaises(ValueError, p.relative_to, P('//C/Foo'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001038 # UNC paths
Antoine Pitrou156b3612013-12-28 19:49:04 +01001039 p = P('//Server/Share/Foo/Bar')
1040 self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar'))
1041 self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar'))
1042 self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar'))
1043 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar'))
1044 self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar'))
1045 self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar'))
1046 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P())
1047 self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001048 # Unrelated paths
Antoine Pitrou156b3612013-12-28 19:49:04 +01001049 self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'))
1050 self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'))
1051 self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'))
1052 self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001053
1054 def test_is_absolute(self):
1055 P = self.cls
1056 # Under NT, only paths with both a drive and a root are absolute
1057 self.assertFalse(P().is_absolute())
1058 self.assertFalse(P('a').is_absolute())
1059 self.assertFalse(P('a/b/').is_absolute())
1060 self.assertFalse(P('/').is_absolute())
1061 self.assertFalse(P('/a').is_absolute())
1062 self.assertFalse(P('/a/b/').is_absolute())
1063 self.assertFalse(P('c:').is_absolute())
1064 self.assertFalse(P('c:a').is_absolute())
1065 self.assertFalse(P('c:a/b/').is_absolute())
1066 self.assertTrue(P('c:/').is_absolute())
1067 self.assertTrue(P('c:/a').is_absolute())
1068 self.assertTrue(P('c:/a/b/').is_absolute())
1069 # UNC paths are absolute by definition
1070 self.assertTrue(P('//a/b').is_absolute())
1071 self.assertTrue(P('//a/b/').is_absolute())
1072 self.assertTrue(P('//a/b/c').is_absolute())
1073 self.assertTrue(P('//a/b/c/d').is_absolute())
1074
Serhiy Storchakaa9939022013-12-06 17:14:12 +02001075 def test_join(self):
1076 P = self.cls
1077 p = P('C:/a/b')
1078 pp = p.joinpath('x/y')
1079 self.assertEqual(pp, P('C:/a/b/x/y'))
1080 pp = p.joinpath('/x/y')
1081 self.assertEqual(pp, P('C:/x/y'))
1082 # Joining with a different drive => the first path is ignored, even
1083 # if the second path is relative.
1084 pp = p.joinpath('D:x/y')
1085 self.assertEqual(pp, P('D:x/y'))
1086 pp = p.joinpath('D:/x/y')
1087 self.assertEqual(pp, P('D:/x/y'))
1088 pp = p.joinpath('//host/share/x/y')
1089 self.assertEqual(pp, P('//host/share/x/y'))
1090 # Joining with the same drive => the first path is appended to if
1091 # the second path is relative.
1092 pp = p.joinpath('c:x/y')
1093 self.assertEqual(pp, P('C:/a/b/x/y'))
1094 pp = p.joinpath('c:/x/y')
1095 self.assertEqual(pp, P('C:/x/y'))
1096
1097 def test_div(self):
1098 # Basically the same as joinpath()
1099 P = self.cls
1100 p = P('C:/a/b')
1101 self.assertEqual(p / 'x/y', P('C:/a/b/x/y'))
1102 self.assertEqual(p / 'x' / 'y', P('C:/a/b/x/y'))
1103 self.assertEqual(p / '/x/y', P('C:/x/y'))
1104 self.assertEqual(p / '/x' / 'y', P('C:/x/y'))
1105 # Joining with a different drive => the first path is ignored, even
1106 # if the second path is relative.
1107 self.assertEqual(p / 'D:x/y', P('D:x/y'))
1108 self.assertEqual(p / 'D:' / 'x/y', P('D:x/y'))
1109 self.assertEqual(p / 'D:/x/y', P('D:/x/y'))
1110 self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y'))
1111 self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y'))
1112 # Joining with the same drive => the first path is appended to if
1113 # the second path is relative.
Serhiy Storchaka010ff582013-12-06 17:25:51 +02001114 self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y'))
1115 self.assertEqual(p / 'c:/x/y', P('C:/x/y'))
Serhiy Storchakaa9939022013-12-06 17:14:12 +02001116
Antoine Pitrou31119e42013-11-22 17:38:12 +01001117 def test_is_reserved(self):
1118 P = self.cls
1119 self.assertIs(False, P('').is_reserved())
1120 self.assertIs(False, P('/').is_reserved())
1121 self.assertIs(False, P('/foo/bar').is_reserved())
1122 self.assertIs(True, P('con').is_reserved())
1123 self.assertIs(True, P('NUL').is_reserved())
1124 self.assertIs(True, P('NUL.txt').is_reserved())
1125 self.assertIs(True, P('com1').is_reserved())
1126 self.assertIs(True, P('com9.bar').is_reserved())
1127 self.assertIs(False, P('bar.com9').is_reserved())
1128 self.assertIs(True, P('lpt1').is_reserved())
1129 self.assertIs(True, P('lpt9.bar').is_reserved())
1130 self.assertIs(False, P('bar.lpt9').is_reserved())
1131 # Only the last component matters
1132 self.assertIs(False, P('c:/NUL/con/baz').is_reserved())
1133 # UNC paths are never reserved
1134 self.assertIs(False, P('//my/share/nul/con/aux').is_reserved())
1135
1136
1137class PurePathTest(_BasePurePathTest, unittest.TestCase):
1138 cls = pathlib.PurePath
1139
1140 def test_concrete_class(self):
1141 p = self.cls('a')
1142 self.assertIs(type(p),
1143 pathlib.PureWindowsPath if os.name == 'nt' else pathlib.PurePosixPath)
1144
1145 def test_different_flavours_unequal(self):
1146 p = pathlib.PurePosixPath('a')
1147 q = pathlib.PureWindowsPath('a')
1148 self.assertNotEqual(p, q)
1149
1150 def test_different_flavours_unordered(self):
1151 p = pathlib.PurePosixPath('a')
1152 q = pathlib.PureWindowsPath('a')
1153 with self.assertRaises(TypeError):
1154 p < q
1155 with self.assertRaises(TypeError):
1156 p <= q
1157 with self.assertRaises(TypeError):
1158 p > q
1159 with self.assertRaises(TypeError):
1160 p >= q
1161
1162
1163#
1164# Tests for the concrete classes
1165#
1166
1167# Make sure any symbolic links in the base test path are resolved
1168BASE = os.path.realpath(TESTFN)
1169join = lambda *x: os.path.join(BASE, *x)
1170rel_join = lambda *x: os.path.join(TESTFN, *x)
1171
1172def symlink_skip_reason():
1173 if not pathlib.supports_symlinks:
1174 return "no system support for symlinks"
1175 try:
1176 os.symlink(__file__, BASE)
1177 except OSError as e:
1178 return str(e)
1179 else:
1180 support.unlink(BASE)
1181 return None
1182
1183symlink_skip_reason = symlink_skip_reason()
1184
1185only_nt = unittest.skipIf(os.name != 'nt',
1186 'test requires a Windows-compatible system')
1187only_posix = unittest.skipIf(os.name == 'nt',
1188 'test requires a POSIX-compatible system')
1189with_symlinks = unittest.skipIf(symlink_skip_reason, symlink_skip_reason)
1190
1191
1192@only_posix
1193class PosixPathAsPureTest(PurePosixPathTest):
1194 cls = pathlib.PosixPath
1195
1196@only_nt
1197class WindowsPathAsPureTest(PureWindowsPathTest):
1198 cls = pathlib.WindowsPath
1199
1200
1201class _BasePathTest(object):
1202 """Tests for the FS-accessing functionalities of the Path classes."""
1203
1204 # (BASE)
1205 # |
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001206 # |-- brokenLink -> non-existing
1207 # |-- dirA
1208 # | `-- linkC -> ../dirB
1209 # |-- dirB
1210 # | |-- fileB
1211 # | `-- linkD -> ../dirB
1212 # |-- dirC
1213 # | |-- dirD
1214 # | | `-- fileD
1215 # | `-- fileC
1216 # |-- dirE
Antoine Pitrou31119e42013-11-22 17:38:12 +01001217 # |-- fileA
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001218 # |-- linkA -> fileA
1219 # `-- linkB -> dirB
Antoine Pitrou31119e42013-11-22 17:38:12 +01001220 #
1221
1222 def setUp(self):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001223 def cleanup():
1224 os.chmod(join('dirE'), 0o777)
1225 support.rmtree(BASE)
1226 self.addCleanup(cleanup)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001227 os.mkdir(BASE)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001228 os.mkdir(join('dirA'))
1229 os.mkdir(join('dirB'))
1230 os.mkdir(join('dirC'))
1231 os.mkdir(join('dirC', 'dirD'))
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001232 os.mkdir(join('dirE'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001233 with open(join('fileA'), 'wb') as f:
1234 f.write(b"this is file A\n")
1235 with open(join('dirB', 'fileB'), 'wb') as f:
1236 f.write(b"this is file B\n")
1237 with open(join('dirC', 'fileC'), 'wb') as f:
1238 f.write(b"this is file C\n")
1239 with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
1240 f.write(b"this is file D\n")
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001241 os.chmod(join('dirE'), 0)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001242 if not symlink_skip_reason:
Antoine Pitrou31119e42013-11-22 17:38:12 +01001243 # Relative symlinks
1244 os.symlink('fileA', join('linkA'))
1245 os.symlink('non-existing', join('brokenLink'))
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001246 self.dirlink('dirB', join('linkB'))
1247 self.dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001248 # This one goes upwards but doesn't create a loop
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001249 self.dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD'))
1250
1251 if os.name == 'nt':
1252 # Workaround for http://bugs.python.org/issue13772
1253 def dirlink(self, src, dest):
1254 os.symlink(src, dest, target_is_directory=True)
1255 else:
1256 def dirlink(self, src, dest):
1257 os.symlink(src, dest)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001258
1259 def assertSame(self, path_a, path_b):
1260 self.assertTrue(os.path.samefile(str(path_a), str(path_b)),
1261 "%r and %r don't point to the same file" %
1262 (path_a, path_b))
1263
1264 def assertFileNotFound(self, func, *args, **kwargs):
1265 with self.assertRaises(FileNotFoundError) as cm:
1266 func(*args, **kwargs)
1267 self.assertEqual(cm.exception.errno, errno.ENOENT)
1268
1269 def _test_cwd(self, p):
1270 q = self.cls(os.getcwd())
1271 self.assertEqual(p, q)
1272 self.assertEqual(str(p), str(q))
1273 self.assertIs(type(p), type(q))
1274 self.assertTrue(p.is_absolute())
1275
1276 def test_cwd(self):
1277 p = self.cls.cwd()
1278 self._test_cwd(p)
1279
1280 def test_empty_path(self):
1281 # The empty path points to '.'
1282 p = self.cls('')
1283 self.assertEqual(p.stat(), os.stat('.'))
1284
1285 def test_exists(self):
1286 P = self.cls
1287 p = P(BASE)
1288 self.assertIs(True, p.exists())
1289 self.assertIs(True, (p / 'dirA').exists())
1290 self.assertIs(True, (p / 'fileA').exists())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001291 self.assertIs(False, (p / 'fileA' / 'bah').exists())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001292 if not symlink_skip_reason:
1293 self.assertIs(True, (p / 'linkA').exists())
1294 self.assertIs(True, (p / 'linkB').exists())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001295 self.assertIs(True, (p / 'linkB' / 'fileB').exists())
1296 self.assertIs(False, (p / 'linkA' / 'bah').exists())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001297 self.assertIs(False, (p / 'foo').exists())
1298 self.assertIs(False, P('/xyzzy').exists())
1299
1300 def test_open_common(self):
1301 p = self.cls(BASE)
1302 with (p / 'fileA').open('r') as f:
1303 self.assertIsInstance(f, io.TextIOBase)
1304 self.assertEqual(f.read(), "this is file A\n")
1305 with (p / 'fileA').open('rb') as f:
1306 self.assertIsInstance(f, io.BufferedIOBase)
1307 self.assertEqual(f.read().strip(), b"this is file A")
1308 with (p / 'fileA').open('rb', buffering=0) as f:
1309 self.assertIsInstance(f, io.RawIOBase)
1310 self.assertEqual(f.read().strip(), b"this is file A")
1311
1312 def test_iterdir(self):
1313 P = self.cls
1314 p = P(BASE)
1315 it = p.iterdir()
1316 paths = set(it)
Guido van Rossum6c2d33a2016-01-06 09:42:07 -08001317 expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
Antoine Pitrou31119e42013-11-22 17:38:12 +01001318 if not symlink_skip_reason:
1319 expected += ['linkA', 'linkB', 'brokenLink']
1320 self.assertEqual(paths, { P(BASE, q) for q in expected })
1321
1322 @with_symlinks
1323 def test_iterdir_symlink(self):
1324 # __iter__ on a symlink to a directory
1325 P = self.cls
1326 p = P(BASE, 'linkB')
1327 paths = set(p.iterdir())
1328 expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] }
1329 self.assertEqual(paths, expected)
1330
1331 def test_iterdir_nodir(self):
1332 # __iter__ on something that is not a directory
1333 p = self.cls(BASE, 'fileA')
1334 with self.assertRaises(OSError) as cm:
1335 next(p.iterdir())
1336 # ENOENT or EINVAL under Windows, ENOTDIR otherwise
1337 # (see issue #12802)
1338 self.assertIn(cm.exception.errno, (errno.ENOTDIR,
1339 errno.ENOENT, errno.EINVAL))
1340
1341 def test_glob_common(self):
1342 def _check(glob, expected):
1343 self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1344 P = self.cls
1345 p = P(BASE)
1346 it = p.glob("fileA")
1347 self.assertIsInstance(it, collections.Iterator)
1348 _check(it, ["fileA"])
1349 _check(p.glob("fileB"), [])
1350 _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
1351 if symlink_skip_reason:
1352 _check(p.glob("*A"), ['dirA', 'fileA'])
1353 else:
1354 _check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
1355 if symlink_skip_reason:
1356 _check(p.glob("*B/*"), ['dirB/fileB'])
1357 else:
1358 _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
1359 'linkB/fileB', 'linkB/linkD'])
1360 if symlink_skip_reason:
1361 _check(p.glob("*/fileB"), ['dirB/fileB'])
1362 else:
1363 _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1364
1365 def test_rglob_common(self):
1366 def _check(glob, expected):
1367 self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1368 P = self.cls
1369 p = P(BASE)
1370 it = p.rglob("fileA")
1371 self.assertIsInstance(it, collections.Iterator)
1372 # XXX cannot test because of symlink loops in the test setup
1373 #_check(it, ["fileA"])
1374 #_check(p.rglob("fileB"), ["dirB/fileB"])
1375 #_check(p.rglob("*/fileA"), [""])
1376 #_check(p.rglob("*/fileB"), ["dirB/fileB"])
1377 #_check(p.rglob("file*"), ["fileA", "dirB/fileB"])
1378 # No symlink loops here
1379 p = P(BASE, "dirC")
1380 _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1381 _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1382
1383 def test_glob_dotdot(self):
1384 # ".." is not special in globs
1385 P = self.cls
1386 p = P(BASE)
1387 self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
1388 self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
1389 self.assertEqual(set(p.glob("../xyzzy")), set())
1390
1391 def _check_resolve_relative(self, p, expected):
1392 q = p.resolve()
1393 self.assertEqual(q, expected)
1394
1395 def _check_resolve_absolute(self, p, expected):
1396 q = p.resolve()
1397 self.assertEqual(q, expected)
1398
1399 @with_symlinks
1400 def test_resolve_common(self):
1401 P = self.cls
1402 p = P(BASE, 'foo')
1403 with self.assertRaises(OSError) as cm:
1404 p.resolve()
1405 self.assertEqual(cm.exception.errno, errno.ENOENT)
1406 # These are all relative symlinks
1407 p = P(BASE, 'dirB', 'fileB')
1408 self._check_resolve_relative(p, p)
1409 p = P(BASE, 'linkA')
1410 self._check_resolve_relative(p, P(BASE, 'fileA'))
1411 p = P(BASE, 'dirA', 'linkC', 'fileB')
1412 self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1413 p = P(BASE, 'dirB', 'linkD', 'fileB')
1414 self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1415 # Now create absolute symlinks
1416 d = tempfile.mkdtemp(suffix='-dirD')
Victor Stinnerec864692014-07-21 19:19:05 +02001417 self.addCleanup(support.rmtree, d)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001418 os.symlink(os.path.join(d), join('dirA', 'linkX'))
1419 os.symlink(join('dirB'), os.path.join(d, 'linkY'))
1420 p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB')
1421 self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
1422
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001423 @with_symlinks
1424 def test_resolve_dot(self):
1425 # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks
1426 p = self.cls(BASE)
1427 self.dirlink('.', join('0'))
Antoine Pitroucc157512013-12-03 17:13:13 +01001428 self.dirlink(os.path.join('0', '0'), join('1'))
1429 self.dirlink(os.path.join('1', '1'), join('2'))
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001430 q = p / '2'
1431 self.assertEqual(q.resolve(), p)
1432
Antoine Pitrou31119e42013-11-22 17:38:12 +01001433 def test_with(self):
1434 p = self.cls(BASE)
1435 it = p.iterdir()
1436 it2 = p.iterdir()
1437 next(it2)
1438 with p:
1439 pass
1440 # I/O operation on closed path
1441 self.assertRaises(ValueError, next, it)
1442 self.assertRaises(ValueError, next, it2)
1443 self.assertRaises(ValueError, p.open)
1444 self.assertRaises(ValueError, p.resolve)
1445 self.assertRaises(ValueError, p.absolute)
1446 self.assertRaises(ValueError, p.__enter__)
1447
1448 def test_chmod(self):
1449 p = self.cls(BASE) / 'fileA'
1450 mode = p.stat().st_mode
1451 # Clear writable bit
1452 new_mode = mode & ~0o222
1453 p.chmod(new_mode)
1454 self.assertEqual(p.stat().st_mode, new_mode)
1455 # Set writable bit
1456 new_mode = mode | 0o222
1457 p.chmod(new_mode)
1458 self.assertEqual(p.stat().st_mode, new_mode)
1459
1460 # XXX also need a test for lchmod
1461
1462 def test_stat(self):
1463 p = self.cls(BASE) / 'fileA'
1464 st = p.stat()
1465 self.assertEqual(p.stat(), st)
1466 # Change file mode by flipping write bit
1467 p.chmod(st.st_mode ^ 0o222)
1468 self.addCleanup(p.chmod, st.st_mode)
1469 self.assertNotEqual(p.stat(), st)
1470
1471 @with_symlinks
1472 def test_lstat(self):
1473 p = self.cls(BASE)/ 'linkA'
1474 st = p.stat()
1475 self.assertNotEqual(st, p.lstat())
1476
1477 def test_lstat_nosymlink(self):
1478 p = self.cls(BASE) / 'fileA'
1479 st = p.stat()
1480 self.assertEqual(st, p.lstat())
1481
1482 @unittest.skipUnless(pwd, "the pwd module is needed for this test")
1483 def test_owner(self):
1484 p = self.cls(BASE) / 'fileA'
1485 uid = p.stat().st_uid
Antoine Pitrou2cf4b0f2013-11-25 19:51:53 +01001486 try:
1487 name = pwd.getpwuid(uid).pw_name
1488 except KeyError:
1489 self.skipTest(
1490 "user %d doesn't have an entry in the system database" % uid)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001491 self.assertEqual(name, p.owner())
1492
1493 @unittest.skipUnless(grp, "the grp module is needed for this test")
1494 def test_group(self):
1495 p = self.cls(BASE) / 'fileA'
1496 gid = p.stat().st_gid
Antoine Pitrou2cf4b0f2013-11-25 19:51:53 +01001497 try:
1498 name = grp.getgrgid(gid).gr_name
1499 except KeyError:
1500 self.skipTest(
1501 "group %d doesn't have an entry in the system database" % gid)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001502 self.assertEqual(name, p.group())
1503
1504 def test_unlink(self):
1505 p = self.cls(BASE) / 'fileA'
1506 p.unlink()
1507 self.assertFileNotFound(p.stat)
1508 self.assertFileNotFound(p.unlink)
1509
1510 def test_rmdir(self):
1511 p = self.cls(BASE) / 'dirA'
1512 for q in p.iterdir():
1513 q.unlink()
1514 p.rmdir()
1515 self.assertFileNotFound(p.stat)
1516 self.assertFileNotFound(p.unlink)
1517
1518 def test_rename(self):
1519 P = self.cls(BASE)
1520 p = P / 'fileA'
1521 size = p.stat().st_size
1522 # Renaming to another path
1523 q = P / 'dirA' / 'fileAA'
1524 p.rename(q)
1525 self.assertEqual(q.stat().st_size, size)
1526 self.assertFileNotFound(p.stat)
1527 # Renaming to a str of a relative path
1528 r = rel_join('fileAAA')
1529 q.rename(r)
1530 self.assertEqual(os.stat(r).st_size, size)
1531 self.assertFileNotFound(q.stat)
1532
1533 def test_replace(self):
1534 P = self.cls(BASE)
1535 p = P / 'fileA'
1536 size = p.stat().st_size
1537 # Replacing a non-existing path
1538 q = P / 'dirA' / 'fileAA'
1539 p.replace(q)
1540 self.assertEqual(q.stat().st_size, size)
1541 self.assertFileNotFound(p.stat)
1542 # Replacing another (existing) path
1543 r = rel_join('dirB', 'fileB')
1544 q.replace(r)
1545 self.assertEqual(os.stat(r).st_size, size)
1546 self.assertFileNotFound(q.stat)
1547
1548 def test_touch_common(self):
1549 P = self.cls(BASE)
1550 p = P / 'newfileA'
1551 self.assertFalse(p.exists())
1552 p.touch()
1553 self.assertTrue(p.exists())
Antoine Pitrou0f575642013-11-22 23:20:08 +01001554 st = p.stat()
1555 old_mtime = st.st_mtime
1556 old_mtime_ns = st.st_mtime_ns
Antoine Pitrou31119e42013-11-22 17:38:12 +01001557 # Rewind the mtime sufficiently far in the past to work around
1558 # filesystem-specific timestamp granularity.
1559 os.utime(str(p), (old_mtime - 10, old_mtime - 10))
Antoine Pitroubb6694d2013-11-23 01:32:53 +01001560 # The file mtime should be refreshed by calling touch() again
Antoine Pitrou31119e42013-11-22 17:38:12 +01001561 p.touch()
Antoine Pitrou0f575642013-11-22 23:20:08 +01001562 st = p.stat()
Antoine Pitrou2cf39172013-11-23 15:25:59 +01001563 self.assertGreaterEqual(st.st_mtime_ns, old_mtime_ns)
1564 self.assertGreaterEqual(st.st_mtime, old_mtime)
Antoine Pitroubb6694d2013-11-23 01:32:53 +01001565 # Now with exist_ok=False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001566 p = P / 'newfileB'
1567 self.assertFalse(p.exists())
1568 p.touch(mode=0o700, exist_ok=False)
1569 self.assertTrue(p.exists())
1570 self.assertRaises(OSError, p.touch, exist_ok=False)
1571
Antoine Pitrou8b784932013-11-23 14:52:39 +01001572 def test_touch_nochange(self):
1573 P = self.cls(BASE)
1574 p = P / 'fileA'
1575 p.touch()
1576 with p.open('rb') as f:
1577 self.assertEqual(f.read().strip(), b"this is file A")
1578
Antoine Pitrou31119e42013-11-22 17:38:12 +01001579 def test_mkdir(self):
1580 P = self.cls(BASE)
1581 p = P / 'newdirA'
1582 self.assertFalse(p.exists())
1583 p.mkdir()
1584 self.assertTrue(p.exists())
1585 self.assertTrue(p.is_dir())
1586 with self.assertRaises(OSError) as cm:
1587 p.mkdir()
1588 self.assertEqual(cm.exception.errno, errno.EEXIST)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001589
1590 def test_mkdir_parents(self):
1591 # Creating a chain of directories
1592 p = self.cls(BASE, 'newdirB', 'newdirC')
1593 self.assertFalse(p.exists())
1594 with self.assertRaises(OSError) as cm:
1595 p.mkdir()
1596 self.assertEqual(cm.exception.errno, errno.ENOENT)
1597 p.mkdir(parents=True)
1598 self.assertTrue(p.exists())
1599 self.assertTrue(p.is_dir())
1600 with self.assertRaises(OSError) as cm:
1601 p.mkdir(parents=True)
1602 self.assertEqual(cm.exception.errno, errno.EEXIST)
Antoine Pitrou0048c982013-12-16 20:22:37 +01001603 # test `mode` arg
1604 mode = stat.S_IMODE(p.stat().st_mode) # default mode
1605 p = self.cls(BASE, 'newdirD', 'newdirE')
1606 p.mkdir(0o555, parents=True)
1607 self.assertTrue(p.exists())
1608 self.assertTrue(p.is_dir())
1609 if os.name != 'nt':
1610 # the directory's permissions follow the mode argument
Gregory P. Smithb599c612014-01-20 01:10:33 -08001611 self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode)
Antoine Pitrou0048c982013-12-16 20:22:37 +01001612 # the parent's permissions follow the default process settings
1613 self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001614
1615 @with_symlinks
1616 def test_symlink_to(self):
1617 P = self.cls(BASE)
1618 target = P / 'fileA'
1619 # Symlinking a path target
1620 link = P / 'dirA' / 'linkAA'
1621 link.symlink_to(target)
1622 self.assertEqual(link.stat(), target.stat())
1623 self.assertNotEqual(link.lstat(), target.stat())
1624 # Symlinking a str target
1625 link = P / 'dirA' / 'linkAAA'
1626 link.symlink_to(str(target))
1627 self.assertEqual(link.stat(), target.stat())
1628 self.assertNotEqual(link.lstat(), target.stat())
1629 self.assertFalse(link.is_dir())
1630 # Symlinking to a directory
1631 target = P / 'dirB'
1632 link = P / 'dirA' / 'linkAAAA'
1633 link.symlink_to(target, target_is_directory=True)
1634 self.assertEqual(link.stat(), target.stat())
1635 self.assertNotEqual(link.lstat(), target.stat())
1636 self.assertTrue(link.is_dir())
1637 self.assertTrue(list(link.iterdir()))
1638
1639 def test_is_dir(self):
1640 P = self.cls(BASE)
1641 self.assertTrue((P / 'dirA').is_dir())
1642 self.assertFalse((P / 'fileA').is_dir())
1643 self.assertFalse((P / 'non-existing').is_dir())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001644 self.assertFalse((P / 'fileA' / 'bah').is_dir())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001645 if not symlink_skip_reason:
1646 self.assertFalse((P / 'linkA').is_dir())
1647 self.assertTrue((P / 'linkB').is_dir())
1648 self.assertFalse((P/ 'brokenLink').is_dir())
1649
1650 def test_is_file(self):
1651 P = self.cls(BASE)
1652 self.assertTrue((P / 'fileA').is_file())
1653 self.assertFalse((P / 'dirA').is_file())
1654 self.assertFalse((P / 'non-existing').is_file())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001655 self.assertFalse((P / 'fileA' / 'bah').is_file())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001656 if not symlink_skip_reason:
1657 self.assertTrue((P / 'linkA').is_file())
1658 self.assertFalse((P / 'linkB').is_file())
1659 self.assertFalse((P/ 'brokenLink').is_file())
1660
1661 def test_is_symlink(self):
1662 P = self.cls(BASE)
1663 self.assertFalse((P / 'fileA').is_symlink())
1664 self.assertFalse((P / 'dirA').is_symlink())
1665 self.assertFalse((P / 'non-existing').is_symlink())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001666 self.assertFalse((P / 'fileA' / 'bah').is_symlink())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001667 if not symlink_skip_reason:
1668 self.assertTrue((P / 'linkA').is_symlink())
1669 self.assertTrue((P / 'linkB').is_symlink())
1670 self.assertTrue((P/ 'brokenLink').is_symlink())
1671
1672 def test_is_fifo_false(self):
1673 P = self.cls(BASE)
1674 self.assertFalse((P / 'fileA').is_fifo())
1675 self.assertFalse((P / 'dirA').is_fifo())
1676 self.assertFalse((P / 'non-existing').is_fifo())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001677 self.assertFalse((P / 'fileA' / 'bah').is_fifo())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001678
1679 @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required")
1680 def test_is_fifo_true(self):
1681 P = self.cls(BASE, 'myfifo')
1682 os.mkfifo(str(P))
1683 self.assertTrue(P.is_fifo())
1684 self.assertFalse(P.is_socket())
1685 self.assertFalse(P.is_file())
1686
1687 def test_is_socket_false(self):
1688 P = self.cls(BASE)
1689 self.assertFalse((P / 'fileA').is_socket())
1690 self.assertFalse((P / 'dirA').is_socket())
1691 self.assertFalse((P / 'non-existing').is_socket())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001692 self.assertFalse((P / 'fileA' / 'bah').is_socket())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001693
1694 @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
1695 def test_is_socket_true(self):
1696 P = self.cls(BASE, 'mysock')
Antoine Pitrou330ce592013-11-22 18:05:06 +01001697 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001698 self.addCleanup(sock.close)
Antoine Pitrou330ce592013-11-22 18:05:06 +01001699 try:
1700 sock.bind(str(P))
1701 except OSError as e:
1702 if "AF_UNIX path too long" in str(e):
1703 self.skipTest("cannot bind Unix socket: " + str(e))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001704 self.assertTrue(P.is_socket())
1705 self.assertFalse(P.is_fifo())
1706 self.assertFalse(P.is_file())
1707
1708 def test_is_block_device_false(self):
1709 P = self.cls(BASE)
1710 self.assertFalse((P / 'fileA').is_block_device())
1711 self.assertFalse((P / 'dirA').is_block_device())
1712 self.assertFalse((P / 'non-existing').is_block_device())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001713 self.assertFalse((P / 'fileA' / 'bah').is_block_device())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001714
1715 def test_is_char_device_false(self):
1716 P = self.cls(BASE)
1717 self.assertFalse((P / 'fileA').is_char_device())
1718 self.assertFalse((P / 'dirA').is_char_device())
1719 self.assertFalse((P / 'non-existing').is_char_device())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001720 self.assertFalse((P / 'fileA' / 'bah').is_char_device())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001721
1722 def test_is_char_device_true(self):
1723 # Under Unix, /dev/null should generally be a char device
1724 P = self.cls('/dev/null')
1725 if not P.exists():
1726 self.skipTest("/dev/null required")
1727 self.assertTrue(P.is_char_device())
1728 self.assertFalse(P.is_block_device())
1729 self.assertFalse(P.is_file())
1730
1731 def test_pickling_common(self):
1732 p = self.cls(BASE, 'fileA')
1733 for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
1734 dumped = pickle.dumps(p, proto)
1735 pp = pickle.loads(dumped)
1736 self.assertEqual(pp.stat(), p.stat())
1737
1738 def test_parts_interning(self):
1739 P = self.cls
1740 p = P('/usr/bin/foo')
1741 q = P('/usr/local/bin')
1742 # 'usr'
1743 self.assertIs(p.parts[1], q.parts[1])
1744 # 'bin'
1745 self.assertIs(p.parts[2], q.parts[3])
1746
Antoine Pitrouc274fd22013-12-16 19:57:41 +01001747 def _check_complex_symlinks(self, link0_target):
1748 # Test solving a non-looping chain of symlinks (issue #19887)
1749 P = self.cls(BASE)
1750 self.dirlink(os.path.join('link0', 'link0'), join('link1'))
1751 self.dirlink(os.path.join('link1', 'link1'), join('link2'))
1752 self.dirlink(os.path.join('link2', 'link2'), join('link3'))
1753 self.dirlink(link0_target, join('link0'))
1754
1755 # Resolve absolute paths
1756 p = (P / 'link0').resolve()
1757 self.assertEqual(p, P)
1758 self.assertEqual(str(p), BASE)
1759 p = (P / 'link1').resolve()
1760 self.assertEqual(p, P)
1761 self.assertEqual(str(p), BASE)
1762 p = (P / 'link2').resolve()
1763 self.assertEqual(p, P)
1764 self.assertEqual(str(p), BASE)
1765 p = (P / 'link3').resolve()
1766 self.assertEqual(p, P)
1767 self.assertEqual(str(p), BASE)
1768
1769 # Resolve relative paths
1770 old_path = os.getcwd()
1771 os.chdir(BASE)
1772 try:
1773 p = self.cls('link0').resolve()
1774 self.assertEqual(p, P)
1775 self.assertEqual(str(p), BASE)
1776 p = self.cls('link1').resolve()
1777 self.assertEqual(p, P)
1778 self.assertEqual(str(p), BASE)
1779 p = self.cls('link2').resolve()
1780 self.assertEqual(p, P)
1781 self.assertEqual(str(p), BASE)
1782 p = self.cls('link3').resolve()
1783 self.assertEqual(p, P)
1784 self.assertEqual(str(p), BASE)
1785 finally:
1786 os.chdir(old_path)
1787
1788 @with_symlinks
1789 def test_complex_symlinks_absolute(self):
1790 self._check_complex_symlinks(BASE)
1791
1792 @with_symlinks
1793 def test_complex_symlinks_relative(self):
1794 self._check_complex_symlinks('.')
1795
1796 @with_symlinks
1797 def test_complex_symlinks_relative_dot_dot(self):
1798 self._check_complex_symlinks(os.path.join('dirA', '..'))
1799
Antoine Pitrou31119e42013-11-22 17:38:12 +01001800
1801class PathTest(_BasePathTest, unittest.TestCase):
1802 cls = pathlib.Path
1803
1804 def test_concrete_class(self):
1805 p = self.cls('a')
1806 self.assertIs(type(p),
1807 pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath)
1808
1809 def test_unsupported_flavour(self):
1810 if os.name == 'nt':
1811 self.assertRaises(NotImplementedError, pathlib.PosixPath)
1812 else:
1813 self.assertRaises(NotImplementedError, pathlib.WindowsPath)
1814
1815
1816@only_posix
1817class PosixPathTest(_BasePathTest, unittest.TestCase):
1818 cls = pathlib.PosixPath
1819
1820 def _check_symlink_loop(self, *args):
1821 path = self.cls(*args)
1822 with self.assertRaises(RuntimeError):
1823 print(path.resolve())
1824
1825 def test_open_mode(self):
1826 old_mask = os.umask(0)
1827 self.addCleanup(os.umask, old_mask)
1828 p = self.cls(BASE)
1829 with (p / 'new_file').open('wb'):
1830 pass
1831 st = os.stat(join('new_file'))
1832 self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
1833 os.umask(0o022)
1834 with (p / 'other_new_file').open('wb'):
1835 pass
1836 st = os.stat(join('other_new_file'))
1837 self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
1838
1839 def test_touch_mode(self):
1840 old_mask = os.umask(0)
1841 self.addCleanup(os.umask, old_mask)
1842 p = self.cls(BASE)
1843 (p / 'new_file').touch()
1844 st = os.stat(join('new_file'))
1845 self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
1846 os.umask(0o022)
1847 (p / 'other_new_file').touch()
1848 st = os.stat(join('other_new_file'))
1849 self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
1850 (p / 'masked_new_file').touch(mode=0o750)
1851 st = os.stat(join('masked_new_file'))
1852 self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
1853
1854 @with_symlinks
1855 def test_resolve_loop(self):
1856 # Loop detection for broken symlinks under POSIX
1857 P = self.cls
1858 # Loops with relative symlinks
1859 os.symlink('linkX/inside', join('linkX'))
1860 self._check_symlink_loop(BASE, 'linkX')
1861 os.symlink('linkY', join('linkY'))
1862 self._check_symlink_loop(BASE, 'linkY')
1863 os.symlink('linkZ/../linkZ', join('linkZ'))
1864 self._check_symlink_loop(BASE, 'linkZ')
1865 # Loops with absolute symlinks
1866 os.symlink(join('linkU/inside'), join('linkU'))
1867 self._check_symlink_loop(BASE, 'linkU')
1868 os.symlink(join('linkV'), join('linkV'))
1869 self._check_symlink_loop(BASE, 'linkV')
1870 os.symlink(join('linkW/../linkW'), join('linkW'))
1871 self._check_symlink_loop(BASE, 'linkW')
1872
1873 def test_glob(self):
1874 P = self.cls
1875 p = P(BASE)
Brett Cannonfe77f4e2013-11-22 16:14:10 -05001876 given = set(p.glob("FILEa"))
1877 expect = set() if not support.fs_is_case_insensitive(BASE) else given
1878 self.assertEqual(given, expect)
Antoine Pitrou2dd38fb2013-11-22 22:26:01 +01001879 self.assertEqual(set(p.glob("FILEa*")), set())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001880
1881 def test_rglob(self):
1882 P = self.cls
1883 p = P(BASE, "dirC")
Brett Cannonfe77f4e2013-11-22 16:14:10 -05001884 given = set(p.rglob("FILEd"))
1885 expect = set() if not support.fs_is_case_insensitive(BASE) else given
1886 self.assertEqual(given, expect)
Antoine Pitrou2dd38fb2013-11-22 22:26:01 +01001887 self.assertEqual(set(p.rglob("FILEd*")), set())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001888
1889
1890@only_nt
1891class WindowsPathTest(_BasePathTest, unittest.TestCase):
1892 cls = pathlib.WindowsPath
1893
1894 def test_glob(self):
1895 P = self.cls
1896 p = P(BASE)
1897 self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
1898
1899 def test_rglob(self):
1900 P = self.cls
1901 p = P(BASE, "dirC")
1902 self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
1903
1904
1905if __name__ == "__main__":
1906 unittest.main()