blob: 11420e2c177b80a209a2bc4de34d8822e696b72e [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 # |
1206 # |-- dirA/
1207 # |-- linkC -> "../dirB"
1208 # |-- dirB/
1209 # | |-- fileB
1210 # |-- linkD -> "../dirB"
1211 # |-- dirC/
1212 # | |-- fileC
1213 # | |-- fileD
1214 # |-- fileA
1215 # |-- linkA -> "fileA"
1216 # |-- linkB -> "dirB"
1217 #
1218
1219 def setUp(self):
1220 os.mkdir(BASE)
Victor Stinnerec864692014-07-21 19:19:05 +02001221 self.addCleanup(support.rmtree, BASE)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001222 os.mkdir(join('dirA'))
1223 os.mkdir(join('dirB'))
1224 os.mkdir(join('dirC'))
1225 os.mkdir(join('dirC', 'dirD'))
1226 with open(join('fileA'), 'wb') as f:
1227 f.write(b"this is file A\n")
1228 with open(join('dirB', 'fileB'), 'wb') as f:
1229 f.write(b"this is file B\n")
1230 with open(join('dirC', 'fileC'), 'wb') as f:
1231 f.write(b"this is file C\n")
1232 with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
1233 f.write(b"this is file D\n")
1234 if not symlink_skip_reason:
Antoine Pitrou31119e42013-11-22 17:38:12 +01001235 # Relative symlinks
1236 os.symlink('fileA', join('linkA'))
1237 os.symlink('non-existing', join('brokenLink'))
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001238 self.dirlink('dirB', join('linkB'))
1239 self.dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC'))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001240 # This one goes upwards but doesn't create a loop
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001241 self.dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD'))
1242
1243 if os.name == 'nt':
1244 # Workaround for http://bugs.python.org/issue13772
1245 def dirlink(self, src, dest):
1246 os.symlink(src, dest, target_is_directory=True)
1247 else:
1248 def dirlink(self, src, dest):
1249 os.symlink(src, dest)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001250
1251 def assertSame(self, path_a, path_b):
1252 self.assertTrue(os.path.samefile(str(path_a), str(path_b)),
1253 "%r and %r don't point to the same file" %
1254 (path_a, path_b))
1255
1256 def assertFileNotFound(self, func, *args, **kwargs):
1257 with self.assertRaises(FileNotFoundError) as cm:
1258 func(*args, **kwargs)
1259 self.assertEqual(cm.exception.errno, errno.ENOENT)
1260
1261 def _test_cwd(self, p):
1262 q = self.cls(os.getcwd())
1263 self.assertEqual(p, q)
1264 self.assertEqual(str(p), str(q))
1265 self.assertIs(type(p), type(q))
1266 self.assertTrue(p.is_absolute())
1267
1268 def test_cwd(self):
1269 p = self.cls.cwd()
1270 self._test_cwd(p)
1271
1272 def test_empty_path(self):
1273 # The empty path points to '.'
1274 p = self.cls('')
1275 self.assertEqual(p.stat(), os.stat('.'))
1276
1277 def test_exists(self):
1278 P = self.cls
1279 p = P(BASE)
1280 self.assertIs(True, p.exists())
1281 self.assertIs(True, (p / 'dirA').exists())
1282 self.assertIs(True, (p / 'fileA').exists())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001283 self.assertIs(False, (p / 'fileA' / 'bah').exists())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001284 if not symlink_skip_reason:
1285 self.assertIs(True, (p / 'linkA').exists())
1286 self.assertIs(True, (p / 'linkB').exists())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001287 self.assertIs(True, (p / 'linkB' / 'fileB').exists())
1288 self.assertIs(False, (p / 'linkA' / 'bah').exists())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001289 self.assertIs(False, (p / 'foo').exists())
1290 self.assertIs(False, P('/xyzzy').exists())
1291
1292 def test_open_common(self):
1293 p = self.cls(BASE)
1294 with (p / 'fileA').open('r') as f:
1295 self.assertIsInstance(f, io.TextIOBase)
1296 self.assertEqual(f.read(), "this is file A\n")
1297 with (p / 'fileA').open('rb') as f:
1298 self.assertIsInstance(f, io.BufferedIOBase)
1299 self.assertEqual(f.read().strip(), b"this is file A")
1300 with (p / 'fileA').open('rb', buffering=0) as f:
1301 self.assertIsInstance(f, io.RawIOBase)
1302 self.assertEqual(f.read().strip(), b"this is file A")
1303
1304 def test_iterdir(self):
1305 P = self.cls
1306 p = P(BASE)
1307 it = p.iterdir()
1308 paths = set(it)
1309 expected = ['dirA', 'dirB', 'dirC', 'fileA']
1310 if not symlink_skip_reason:
1311 expected += ['linkA', 'linkB', 'brokenLink']
1312 self.assertEqual(paths, { P(BASE, q) for q in expected })
1313
1314 @with_symlinks
1315 def test_iterdir_symlink(self):
1316 # __iter__ on a symlink to a directory
1317 P = self.cls
1318 p = P(BASE, 'linkB')
1319 paths = set(p.iterdir())
1320 expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] }
1321 self.assertEqual(paths, expected)
1322
1323 def test_iterdir_nodir(self):
1324 # __iter__ on something that is not a directory
1325 p = self.cls(BASE, 'fileA')
1326 with self.assertRaises(OSError) as cm:
1327 next(p.iterdir())
1328 # ENOENT or EINVAL under Windows, ENOTDIR otherwise
1329 # (see issue #12802)
1330 self.assertIn(cm.exception.errno, (errno.ENOTDIR,
1331 errno.ENOENT, errno.EINVAL))
1332
1333 def test_glob_common(self):
1334 def _check(glob, expected):
1335 self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1336 P = self.cls
1337 p = P(BASE)
1338 it = p.glob("fileA")
1339 self.assertIsInstance(it, collections.Iterator)
1340 _check(it, ["fileA"])
1341 _check(p.glob("fileB"), [])
1342 _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
1343 if symlink_skip_reason:
1344 _check(p.glob("*A"), ['dirA', 'fileA'])
1345 else:
1346 _check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
1347 if symlink_skip_reason:
1348 _check(p.glob("*B/*"), ['dirB/fileB'])
1349 else:
1350 _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
1351 'linkB/fileB', 'linkB/linkD'])
1352 if symlink_skip_reason:
1353 _check(p.glob("*/fileB"), ['dirB/fileB'])
1354 else:
1355 _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1356
1357 def test_rglob_common(self):
1358 def _check(glob, expected):
1359 self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1360 P = self.cls
1361 p = P(BASE)
1362 it = p.rglob("fileA")
1363 self.assertIsInstance(it, collections.Iterator)
1364 # XXX cannot test because of symlink loops in the test setup
1365 #_check(it, ["fileA"])
1366 #_check(p.rglob("fileB"), ["dirB/fileB"])
1367 #_check(p.rglob("*/fileA"), [""])
1368 #_check(p.rglob("*/fileB"), ["dirB/fileB"])
1369 #_check(p.rglob("file*"), ["fileA", "dirB/fileB"])
1370 # No symlink loops here
1371 p = P(BASE, "dirC")
1372 _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1373 _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1374
1375 def test_glob_dotdot(self):
1376 # ".." is not special in globs
1377 P = self.cls
1378 p = P(BASE)
1379 self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
1380 self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
1381 self.assertEqual(set(p.glob("../xyzzy")), set())
1382
1383 def _check_resolve_relative(self, p, expected):
1384 q = p.resolve()
1385 self.assertEqual(q, expected)
1386
1387 def _check_resolve_absolute(self, p, expected):
1388 q = p.resolve()
1389 self.assertEqual(q, expected)
1390
1391 @with_symlinks
1392 def test_resolve_common(self):
1393 P = self.cls
1394 p = P(BASE, 'foo')
1395 with self.assertRaises(OSError) as cm:
1396 p.resolve()
1397 self.assertEqual(cm.exception.errno, errno.ENOENT)
1398 # These are all relative symlinks
1399 p = P(BASE, 'dirB', 'fileB')
1400 self._check_resolve_relative(p, p)
1401 p = P(BASE, 'linkA')
1402 self._check_resolve_relative(p, P(BASE, 'fileA'))
1403 p = P(BASE, 'dirA', 'linkC', 'fileB')
1404 self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1405 p = P(BASE, 'dirB', 'linkD', 'fileB')
1406 self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1407 # Now create absolute symlinks
1408 d = tempfile.mkdtemp(suffix='-dirD')
Victor Stinnerec864692014-07-21 19:19:05 +02001409 self.addCleanup(support.rmtree, d)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001410 os.symlink(os.path.join(d), join('dirA', 'linkX'))
1411 os.symlink(join('dirB'), os.path.join(d, 'linkY'))
1412 p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB')
1413 self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
1414
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001415 @with_symlinks
1416 def test_resolve_dot(self):
1417 # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks
1418 p = self.cls(BASE)
1419 self.dirlink('.', join('0'))
Antoine Pitroucc157512013-12-03 17:13:13 +01001420 self.dirlink(os.path.join('0', '0'), join('1'))
1421 self.dirlink(os.path.join('1', '1'), join('2'))
Antoine Pitrou51af82c2013-12-03 11:01:08 +01001422 q = p / '2'
1423 self.assertEqual(q.resolve(), p)
1424
Antoine Pitrou31119e42013-11-22 17:38:12 +01001425 def test_with(self):
1426 p = self.cls(BASE)
1427 it = p.iterdir()
1428 it2 = p.iterdir()
1429 next(it2)
1430 with p:
1431 pass
1432 # I/O operation on closed path
1433 self.assertRaises(ValueError, next, it)
1434 self.assertRaises(ValueError, next, it2)
1435 self.assertRaises(ValueError, p.open)
1436 self.assertRaises(ValueError, p.resolve)
1437 self.assertRaises(ValueError, p.absolute)
1438 self.assertRaises(ValueError, p.__enter__)
1439
1440 def test_chmod(self):
1441 p = self.cls(BASE) / 'fileA'
1442 mode = p.stat().st_mode
1443 # Clear writable bit
1444 new_mode = mode & ~0o222
1445 p.chmod(new_mode)
1446 self.assertEqual(p.stat().st_mode, new_mode)
1447 # Set writable bit
1448 new_mode = mode | 0o222
1449 p.chmod(new_mode)
1450 self.assertEqual(p.stat().st_mode, new_mode)
1451
1452 # XXX also need a test for lchmod
1453
1454 def test_stat(self):
1455 p = self.cls(BASE) / 'fileA'
1456 st = p.stat()
1457 self.assertEqual(p.stat(), st)
1458 # Change file mode by flipping write bit
1459 p.chmod(st.st_mode ^ 0o222)
1460 self.addCleanup(p.chmod, st.st_mode)
1461 self.assertNotEqual(p.stat(), st)
1462
1463 @with_symlinks
1464 def test_lstat(self):
1465 p = self.cls(BASE)/ 'linkA'
1466 st = p.stat()
1467 self.assertNotEqual(st, p.lstat())
1468
1469 def test_lstat_nosymlink(self):
1470 p = self.cls(BASE) / 'fileA'
1471 st = p.stat()
1472 self.assertEqual(st, p.lstat())
1473
1474 @unittest.skipUnless(pwd, "the pwd module is needed for this test")
1475 def test_owner(self):
1476 p = self.cls(BASE) / 'fileA'
1477 uid = p.stat().st_uid
Antoine Pitrou2cf4b0f2013-11-25 19:51:53 +01001478 try:
1479 name = pwd.getpwuid(uid).pw_name
1480 except KeyError:
1481 self.skipTest(
1482 "user %d doesn't have an entry in the system database" % uid)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001483 self.assertEqual(name, p.owner())
1484
1485 @unittest.skipUnless(grp, "the grp module is needed for this test")
1486 def test_group(self):
1487 p = self.cls(BASE) / 'fileA'
1488 gid = p.stat().st_gid
Antoine Pitrou2cf4b0f2013-11-25 19:51:53 +01001489 try:
1490 name = grp.getgrgid(gid).gr_name
1491 except KeyError:
1492 self.skipTest(
1493 "group %d doesn't have an entry in the system database" % gid)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001494 self.assertEqual(name, p.group())
1495
1496 def test_unlink(self):
1497 p = self.cls(BASE) / 'fileA'
1498 p.unlink()
1499 self.assertFileNotFound(p.stat)
1500 self.assertFileNotFound(p.unlink)
1501
1502 def test_rmdir(self):
1503 p = self.cls(BASE) / 'dirA'
1504 for q in p.iterdir():
1505 q.unlink()
1506 p.rmdir()
1507 self.assertFileNotFound(p.stat)
1508 self.assertFileNotFound(p.unlink)
1509
1510 def test_rename(self):
1511 P = self.cls(BASE)
1512 p = P / 'fileA'
1513 size = p.stat().st_size
1514 # Renaming to another path
1515 q = P / 'dirA' / 'fileAA'
1516 p.rename(q)
1517 self.assertEqual(q.stat().st_size, size)
1518 self.assertFileNotFound(p.stat)
1519 # Renaming to a str of a relative path
1520 r = rel_join('fileAAA')
1521 q.rename(r)
1522 self.assertEqual(os.stat(r).st_size, size)
1523 self.assertFileNotFound(q.stat)
1524
1525 def test_replace(self):
1526 P = self.cls(BASE)
1527 p = P / 'fileA'
1528 size = p.stat().st_size
1529 # Replacing a non-existing path
1530 q = P / 'dirA' / 'fileAA'
1531 p.replace(q)
1532 self.assertEqual(q.stat().st_size, size)
1533 self.assertFileNotFound(p.stat)
1534 # Replacing another (existing) path
1535 r = rel_join('dirB', 'fileB')
1536 q.replace(r)
1537 self.assertEqual(os.stat(r).st_size, size)
1538 self.assertFileNotFound(q.stat)
1539
1540 def test_touch_common(self):
1541 P = self.cls(BASE)
1542 p = P / 'newfileA'
1543 self.assertFalse(p.exists())
1544 p.touch()
1545 self.assertTrue(p.exists())
Antoine Pitrou0f575642013-11-22 23:20:08 +01001546 st = p.stat()
1547 old_mtime = st.st_mtime
1548 old_mtime_ns = st.st_mtime_ns
Antoine Pitrou31119e42013-11-22 17:38:12 +01001549 # Rewind the mtime sufficiently far in the past to work around
1550 # filesystem-specific timestamp granularity.
1551 os.utime(str(p), (old_mtime - 10, old_mtime - 10))
Antoine Pitroubb6694d2013-11-23 01:32:53 +01001552 # The file mtime should be refreshed by calling touch() again
Antoine Pitrou31119e42013-11-22 17:38:12 +01001553 p.touch()
Antoine Pitrou0f575642013-11-22 23:20:08 +01001554 st = p.stat()
Antoine Pitrou2cf39172013-11-23 15:25:59 +01001555 self.assertGreaterEqual(st.st_mtime_ns, old_mtime_ns)
1556 self.assertGreaterEqual(st.st_mtime, old_mtime)
Antoine Pitroubb6694d2013-11-23 01:32:53 +01001557 # Now with exist_ok=False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001558 p = P / 'newfileB'
1559 self.assertFalse(p.exists())
1560 p.touch(mode=0o700, exist_ok=False)
1561 self.assertTrue(p.exists())
1562 self.assertRaises(OSError, p.touch, exist_ok=False)
1563
Antoine Pitrou8b784932013-11-23 14:52:39 +01001564 def test_touch_nochange(self):
1565 P = self.cls(BASE)
1566 p = P / 'fileA'
1567 p.touch()
1568 with p.open('rb') as f:
1569 self.assertEqual(f.read().strip(), b"this is file A")
1570
Antoine Pitrou31119e42013-11-22 17:38:12 +01001571 def test_mkdir(self):
1572 P = self.cls(BASE)
1573 p = P / 'newdirA'
1574 self.assertFalse(p.exists())
1575 p.mkdir()
1576 self.assertTrue(p.exists())
1577 self.assertTrue(p.is_dir())
1578 with self.assertRaises(OSError) as cm:
1579 p.mkdir()
1580 self.assertEqual(cm.exception.errno, errno.EEXIST)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001581
1582 def test_mkdir_parents(self):
1583 # Creating a chain of directories
1584 p = self.cls(BASE, 'newdirB', 'newdirC')
1585 self.assertFalse(p.exists())
1586 with self.assertRaises(OSError) as cm:
1587 p.mkdir()
1588 self.assertEqual(cm.exception.errno, errno.ENOENT)
1589 p.mkdir(parents=True)
1590 self.assertTrue(p.exists())
1591 self.assertTrue(p.is_dir())
1592 with self.assertRaises(OSError) as cm:
1593 p.mkdir(parents=True)
1594 self.assertEqual(cm.exception.errno, errno.EEXIST)
Antoine Pitrou0048c982013-12-16 20:22:37 +01001595 # test `mode` arg
1596 mode = stat.S_IMODE(p.stat().st_mode) # default mode
1597 p = self.cls(BASE, 'newdirD', 'newdirE')
1598 p.mkdir(0o555, parents=True)
1599 self.assertTrue(p.exists())
1600 self.assertTrue(p.is_dir())
1601 if os.name != 'nt':
1602 # the directory's permissions follow the mode argument
Gregory P. Smithb599c612014-01-20 01:10:33 -08001603 self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode)
Antoine Pitrou0048c982013-12-16 20:22:37 +01001604 # the parent's permissions follow the default process settings
1605 self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001606
1607 @with_symlinks
1608 def test_symlink_to(self):
1609 P = self.cls(BASE)
1610 target = P / 'fileA'
1611 # Symlinking a path target
1612 link = P / 'dirA' / 'linkAA'
1613 link.symlink_to(target)
1614 self.assertEqual(link.stat(), target.stat())
1615 self.assertNotEqual(link.lstat(), target.stat())
1616 # Symlinking a str target
1617 link = P / 'dirA' / 'linkAAA'
1618 link.symlink_to(str(target))
1619 self.assertEqual(link.stat(), target.stat())
1620 self.assertNotEqual(link.lstat(), target.stat())
1621 self.assertFalse(link.is_dir())
1622 # Symlinking to a directory
1623 target = P / 'dirB'
1624 link = P / 'dirA' / 'linkAAAA'
1625 link.symlink_to(target, target_is_directory=True)
1626 self.assertEqual(link.stat(), target.stat())
1627 self.assertNotEqual(link.lstat(), target.stat())
1628 self.assertTrue(link.is_dir())
1629 self.assertTrue(list(link.iterdir()))
1630
1631 def test_is_dir(self):
1632 P = self.cls(BASE)
1633 self.assertTrue((P / 'dirA').is_dir())
1634 self.assertFalse((P / 'fileA').is_dir())
1635 self.assertFalse((P / 'non-existing').is_dir())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001636 self.assertFalse((P / 'fileA' / 'bah').is_dir())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001637 if not symlink_skip_reason:
1638 self.assertFalse((P / 'linkA').is_dir())
1639 self.assertTrue((P / 'linkB').is_dir())
1640 self.assertFalse((P/ 'brokenLink').is_dir())
1641
1642 def test_is_file(self):
1643 P = self.cls(BASE)
1644 self.assertTrue((P / 'fileA').is_file())
1645 self.assertFalse((P / 'dirA').is_file())
1646 self.assertFalse((P / 'non-existing').is_file())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001647 self.assertFalse((P / 'fileA' / 'bah').is_file())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001648 if not symlink_skip_reason:
1649 self.assertTrue((P / 'linkA').is_file())
1650 self.assertFalse((P / 'linkB').is_file())
1651 self.assertFalse((P/ 'brokenLink').is_file())
1652
1653 def test_is_symlink(self):
1654 P = self.cls(BASE)
1655 self.assertFalse((P / 'fileA').is_symlink())
1656 self.assertFalse((P / 'dirA').is_symlink())
1657 self.assertFalse((P / 'non-existing').is_symlink())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001658 self.assertFalse((P / 'fileA' / 'bah').is_symlink())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001659 if not symlink_skip_reason:
1660 self.assertTrue((P / 'linkA').is_symlink())
1661 self.assertTrue((P / 'linkB').is_symlink())
1662 self.assertTrue((P/ 'brokenLink').is_symlink())
1663
1664 def test_is_fifo_false(self):
1665 P = self.cls(BASE)
1666 self.assertFalse((P / 'fileA').is_fifo())
1667 self.assertFalse((P / 'dirA').is_fifo())
1668 self.assertFalse((P / 'non-existing').is_fifo())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001669 self.assertFalse((P / 'fileA' / 'bah').is_fifo())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001670
1671 @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required")
1672 def test_is_fifo_true(self):
1673 P = self.cls(BASE, 'myfifo')
1674 os.mkfifo(str(P))
1675 self.assertTrue(P.is_fifo())
1676 self.assertFalse(P.is_socket())
1677 self.assertFalse(P.is_file())
1678
1679 def test_is_socket_false(self):
1680 P = self.cls(BASE)
1681 self.assertFalse((P / 'fileA').is_socket())
1682 self.assertFalse((P / 'dirA').is_socket())
1683 self.assertFalse((P / 'non-existing').is_socket())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001684 self.assertFalse((P / 'fileA' / 'bah').is_socket())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001685
1686 @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
1687 def test_is_socket_true(self):
1688 P = self.cls(BASE, 'mysock')
Antoine Pitrou330ce592013-11-22 18:05:06 +01001689 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001690 self.addCleanup(sock.close)
Antoine Pitrou330ce592013-11-22 18:05:06 +01001691 try:
1692 sock.bind(str(P))
1693 except OSError as e:
1694 if "AF_UNIX path too long" in str(e):
1695 self.skipTest("cannot bind Unix socket: " + str(e))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001696 self.assertTrue(P.is_socket())
1697 self.assertFalse(P.is_fifo())
1698 self.assertFalse(P.is_file())
1699
1700 def test_is_block_device_false(self):
1701 P = self.cls(BASE)
1702 self.assertFalse((P / 'fileA').is_block_device())
1703 self.assertFalse((P / 'dirA').is_block_device())
1704 self.assertFalse((P / 'non-existing').is_block_device())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001705 self.assertFalse((P / 'fileA' / 'bah').is_block_device())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001706
1707 def test_is_char_device_false(self):
1708 P = self.cls(BASE)
1709 self.assertFalse((P / 'fileA').is_char_device())
1710 self.assertFalse((P / 'dirA').is_char_device())
1711 self.assertFalse((P / 'non-existing').is_char_device())
Antoine Pitrou2b2852b2014-10-30 23:14:03 +01001712 self.assertFalse((P / 'fileA' / 'bah').is_char_device())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001713
1714 def test_is_char_device_true(self):
1715 # Under Unix, /dev/null should generally be a char device
1716 P = self.cls('/dev/null')
1717 if not P.exists():
1718 self.skipTest("/dev/null required")
1719 self.assertTrue(P.is_char_device())
1720 self.assertFalse(P.is_block_device())
1721 self.assertFalse(P.is_file())
1722
1723 def test_pickling_common(self):
1724 p = self.cls(BASE, 'fileA')
1725 for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
1726 dumped = pickle.dumps(p, proto)
1727 pp = pickle.loads(dumped)
1728 self.assertEqual(pp.stat(), p.stat())
1729
1730 def test_parts_interning(self):
1731 P = self.cls
1732 p = P('/usr/bin/foo')
1733 q = P('/usr/local/bin')
1734 # 'usr'
1735 self.assertIs(p.parts[1], q.parts[1])
1736 # 'bin'
1737 self.assertIs(p.parts[2], q.parts[3])
1738
Antoine Pitrouc274fd22013-12-16 19:57:41 +01001739 def _check_complex_symlinks(self, link0_target):
1740 # Test solving a non-looping chain of symlinks (issue #19887)
1741 P = self.cls(BASE)
1742 self.dirlink(os.path.join('link0', 'link0'), join('link1'))
1743 self.dirlink(os.path.join('link1', 'link1'), join('link2'))
1744 self.dirlink(os.path.join('link2', 'link2'), join('link3'))
1745 self.dirlink(link0_target, join('link0'))
1746
1747 # Resolve absolute paths
1748 p = (P / 'link0').resolve()
1749 self.assertEqual(p, P)
1750 self.assertEqual(str(p), BASE)
1751 p = (P / 'link1').resolve()
1752 self.assertEqual(p, P)
1753 self.assertEqual(str(p), BASE)
1754 p = (P / 'link2').resolve()
1755 self.assertEqual(p, P)
1756 self.assertEqual(str(p), BASE)
1757 p = (P / 'link3').resolve()
1758 self.assertEqual(p, P)
1759 self.assertEqual(str(p), BASE)
1760
1761 # Resolve relative paths
1762 old_path = os.getcwd()
1763 os.chdir(BASE)
1764 try:
1765 p = self.cls('link0').resolve()
1766 self.assertEqual(p, P)
1767 self.assertEqual(str(p), BASE)
1768 p = self.cls('link1').resolve()
1769 self.assertEqual(p, P)
1770 self.assertEqual(str(p), BASE)
1771 p = self.cls('link2').resolve()
1772 self.assertEqual(p, P)
1773 self.assertEqual(str(p), BASE)
1774 p = self.cls('link3').resolve()
1775 self.assertEqual(p, P)
1776 self.assertEqual(str(p), BASE)
1777 finally:
1778 os.chdir(old_path)
1779
1780 @with_symlinks
1781 def test_complex_symlinks_absolute(self):
1782 self._check_complex_symlinks(BASE)
1783
1784 @with_symlinks
1785 def test_complex_symlinks_relative(self):
1786 self._check_complex_symlinks('.')
1787
1788 @with_symlinks
1789 def test_complex_symlinks_relative_dot_dot(self):
1790 self._check_complex_symlinks(os.path.join('dirA', '..'))
1791
Antoine Pitrou31119e42013-11-22 17:38:12 +01001792
1793class PathTest(_BasePathTest, unittest.TestCase):
1794 cls = pathlib.Path
1795
1796 def test_concrete_class(self):
1797 p = self.cls('a')
1798 self.assertIs(type(p),
1799 pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath)
1800
1801 def test_unsupported_flavour(self):
1802 if os.name == 'nt':
1803 self.assertRaises(NotImplementedError, pathlib.PosixPath)
1804 else:
1805 self.assertRaises(NotImplementedError, pathlib.WindowsPath)
1806
1807
1808@only_posix
1809class PosixPathTest(_BasePathTest, unittest.TestCase):
1810 cls = pathlib.PosixPath
1811
1812 def _check_symlink_loop(self, *args):
1813 path = self.cls(*args)
1814 with self.assertRaises(RuntimeError):
1815 print(path.resolve())
1816
1817 def test_open_mode(self):
1818 old_mask = os.umask(0)
1819 self.addCleanup(os.umask, old_mask)
1820 p = self.cls(BASE)
1821 with (p / 'new_file').open('wb'):
1822 pass
1823 st = os.stat(join('new_file'))
1824 self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
1825 os.umask(0o022)
1826 with (p / 'other_new_file').open('wb'):
1827 pass
1828 st = os.stat(join('other_new_file'))
1829 self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
1830
1831 def test_touch_mode(self):
1832 old_mask = os.umask(0)
1833 self.addCleanup(os.umask, old_mask)
1834 p = self.cls(BASE)
1835 (p / 'new_file').touch()
1836 st = os.stat(join('new_file'))
1837 self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
1838 os.umask(0o022)
1839 (p / 'other_new_file').touch()
1840 st = os.stat(join('other_new_file'))
1841 self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
1842 (p / 'masked_new_file').touch(mode=0o750)
1843 st = os.stat(join('masked_new_file'))
1844 self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
1845
1846 @with_symlinks
1847 def test_resolve_loop(self):
1848 # Loop detection for broken symlinks under POSIX
1849 P = self.cls
1850 # Loops with relative symlinks
1851 os.symlink('linkX/inside', join('linkX'))
1852 self._check_symlink_loop(BASE, 'linkX')
1853 os.symlink('linkY', join('linkY'))
1854 self._check_symlink_loop(BASE, 'linkY')
1855 os.symlink('linkZ/../linkZ', join('linkZ'))
1856 self._check_symlink_loop(BASE, 'linkZ')
1857 # Loops with absolute symlinks
1858 os.symlink(join('linkU/inside'), join('linkU'))
1859 self._check_symlink_loop(BASE, 'linkU')
1860 os.symlink(join('linkV'), join('linkV'))
1861 self._check_symlink_loop(BASE, 'linkV')
1862 os.symlink(join('linkW/../linkW'), join('linkW'))
1863 self._check_symlink_loop(BASE, 'linkW')
1864
1865 def test_glob(self):
1866 P = self.cls
1867 p = P(BASE)
Brett Cannonfe77f4e2013-11-22 16:14:10 -05001868 given = set(p.glob("FILEa"))
1869 expect = set() if not support.fs_is_case_insensitive(BASE) else given
1870 self.assertEqual(given, expect)
Antoine Pitrou2dd38fb2013-11-22 22:26:01 +01001871 self.assertEqual(set(p.glob("FILEa*")), set())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001872
1873 def test_rglob(self):
1874 P = self.cls
1875 p = P(BASE, "dirC")
Brett Cannonfe77f4e2013-11-22 16:14:10 -05001876 given = set(p.rglob("FILEd"))
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.rglob("FILEd*")), set())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001880
1881
1882@only_nt
1883class WindowsPathTest(_BasePathTest, unittest.TestCase):
1884 cls = pathlib.WindowsPath
1885
1886 def test_glob(self):
1887 P = self.cls
1888 p = P(BASE)
1889 self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
1890
1891 def test_rglob(self):
1892 P = self.cls
1893 p = P(BASE, "dirC")
1894 self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
1895
1896
1897if __name__ == "__main__":
1898 unittest.main()