1import collections.abc
2import io
3import os
4import sys
5import errno
6import pathlib
7import pickle
8import socket
9import stat
10import tempfile
11import unittest
12from unittest import mock
13
14from test import support
15from test.support import TESTFN, FakePath
16
17try:
18    import grp, pwd
19except ImportError:
20    grp = pwd = None
21
22
23class _BaseFlavourTest(object):
24
25    def _check_parse_parts(self, arg, expected):
26        f = self.flavour.parse_parts
27        sep = self.flavour.sep
28        altsep = self.flavour.altsep
29        actual = f([x.replace('/', sep) for x in arg])
30        self.assertEqual(actual, expected)
31        if altsep:
32            actual = f([x.replace('/', altsep) for x in arg])
33            self.assertEqual(actual, expected)
34
35    def test_parse_parts_common(self):
36        check = self._check_parse_parts
37        sep = self.flavour.sep
38        # Unanchored parts.
39        check([],                   ('', '', []))
40        check(['a'],                ('', '', ['a']))
41        check(['a/'],               ('', '', ['a']))
42        check(['a', 'b'],           ('', '', ['a', 'b']))
43        # Expansion.
44        check(['a/b'],              ('', '', ['a', 'b']))
45        check(['a/b/'],             ('', '', ['a', 'b']))
46        check(['a', 'b/c', 'd'],    ('', '', ['a', 'b', 'c', 'd']))
47        # Collapsing and stripping excess slashes.
48        check(['a', 'b//c', 'd'],   ('', '', ['a', 'b', 'c', 'd']))
49        check(['a', 'b/c/', 'd'],   ('', '', ['a', 'b', 'c', 'd']))
50        # Eliminating standalone dots.
51        check(['.'],                ('', '', []))
52        check(['.', '.', 'b'],      ('', '', ['b']))
53        check(['a', '.', 'b'],      ('', '', ['a', 'b']))
54        check(['a', '.', '.'],      ('', '', ['a']))
55        # The first part is anchored.
56        check(['/a/b'],             ('', sep, [sep, 'a', 'b']))
57        check(['/a', 'b'],          ('', sep, [sep, 'a', 'b']))
58        check(['/a/', 'b'],         ('', sep, [sep, 'a', 'b']))
59        # Ignoring parts before an anchored part.
60        check(['a', '/b', 'c'],     ('', sep, [sep, 'b', 'c']))
61        check(['a', '/b', '/c'],    ('', sep, [sep, 'c']))
62
63
64class PosixFlavourTest(_BaseFlavourTest, unittest.TestCase):
65    flavour = pathlib._posix_flavour
66
67    def test_parse_parts(self):
68        check = self._check_parse_parts
69        # Collapsing of excess leading slashes, except for the double-slash
70        # special case.
71        check(['//a', 'b'],             ('', '//', ['//', 'a', 'b']))
72        check(['///a', 'b'],            ('', '/', ['/', 'a', 'b']))
73        check(['////a', 'b'],           ('', '/', ['/', 'a', 'b']))
74        # Paths which look like NT paths aren't treated specially.
75        check(['c:a'],                  ('', '', ['c:a']))
76        check(['c:\\a'],                ('', '', ['c:\\a']))
77        check(['\\a'],                  ('', '', ['\\a']))
78
79    def test_splitroot(self):
80        f = self.flavour.splitroot
81        self.assertEqual(f(''), ('', '', ''))
82        self.assertEqual(f('a'), ('', '', 'a'))
83        self.assertEqual(f('a/b'), ('', '', 'a/b'))
84        self.assertEqual(f('a/b/'), ('', '', 'a/b/'))
85        self.assertEqual(f('/a'), ('', '/', 'a'))
86        self.assertEqual(f('/a/b'), ('', '/', 'a/b'))
87        self.assertEqual(f('/a/b/'), ('', '/', 'a/b/'))
88        # The root is collapsed when there are redundant slashes
89        # except when there are exactly two leading slashes, which
90        # is a special case in POSIX.
91        self.assertEqual(f('//a'), ('', '//', 'a'))
92        self.assertEqual(f('///a'), ('', '/', 'a'))
93        self.assertEqual(f('///a/b'), ('', '/', 'a/b'))
94        # Paths which look like NT paths aren't treated specially.
95        self.assertEqual(f('c:/a/b'), ('', '', 'c:/a/b'))
96        self.assertEqual(f('\\/a/b'), ('', '', '\\/a/b'))
97        self.assertEqual(f('\\a\\b'), ('', '', '\\a\\b'))
98
99
100class NTFlavourTest(_BaseFlavourTest, unittest.TestCase):
101    flavour = pathlib._windows_flavour
102
103    def test_parse_parts(self):
104        check = self._check_parse_parts
105        # First part is anchored.
106        check(['c:'],                   ('c:', '', ['c:']))
107        check(['c:/'],                  ('c:', '\\', ['c:\\']))
108        check(['/'],                    ('', '\\', ['\\']))
109        check(['c:a'],                  ('c:', '', ['c:', 'a']))
110        check(['c:/a'],                 ('c:', '\\', ['c:\\', 'a']))
111        check(['/a'],                   ('', '\\', ['\\', 'a']))
112        # UNC paths.
113        check(['//a/b'],                ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
114        check(['//a/b/'],               ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
115        check(['//a/b/c'],              ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c']))
116        # Second part is anchored, so that the first part is ignored.
117        check(['a', 'Z:b', 'c'],        ('Z:', '', ['Z:', 'b', 'c']))
118        check(['a', 'Z:/b', 'c'],       ('Z:', '\\', ['Z:\\', 'b', 'c']))
119        # UNC paths.
120        check(['a', '//b/c', 'd'],      ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
121        # Collapsing and stripping excess slashes.
122        check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd']))
123        # UNC paths.
124        check(['a', '//b/c//', 'd'],    ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
125        # Extended paths.
126        check(['//?/c:/'],              ('\\\\?\\c:', '\\', ['\\\\?\\c:\\']))
127        check(['//?/c:/a'],             ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a']))
128        check(['//?/c:/a', '/b'],       ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b']))
129        # Extended UNC paths (format is "\\?\UNC\server\share").
130        check(['//?/UNC/b/c'],          ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\']))
131        check(['//?/UNC/b/c/d'],        ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd']))
132        # Second part has a root but not drive.
133        check(['a', '/b', 'c'],         ('', '\\', ['\\', 'b', 'c']))
134        check(['Z:/a', '/b', 'c'],      ('Z:', '\\', ['Z:\\', 'b', 'c']))
135        check(['//?/Z:/a', '/b', 'c'],  ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c']))
136
137    def test_splitroot(self):
138        f = self.flavour.splitroot
139        self.assertEqual(f(''), ('', '', ''))
140        self.assertEqual(f('a'), ('', '', 'a'))
141        self.assertEqual(f('a\\b'), ('', '', 'a\\b'))
142        self.assertEqual(f('\\a'), ('', '\\', 'a'))
143        self.assertEqual(f('\\a\\b'), ('', '\\', 'a\\b'))
144        self.assertEqual(f('c:a\\b'), ('c:', '', 'a\\b'))
145        self.assertEqual(f('c:\\a\\b'), ('c:', '\\', 'a\\b'))
146        # Redundant slashes in the root are collapsed.
147        self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
148        self.assertEqual(f('\\\\\\a/b'), ('', '\\', 'a/b'))
149        self.assertEqual(f('c:\\\\a'), ('c:', '\\', 'a'))
150        self.assertEqual(f('c:\\\\\\a/b'), ('c:', '\\', 'a/b'))
151        # Valid UNC paths.
152        self.assertEqual(f('\\\\a\\b'), ('\\\\a\\b', '\\', ''))
153        self.assertEqual(f('\\\\a\\b\\'), ('\\\\a\\b', '\\', ''))
154        self.assertEqual(f('\\\\a\\b\\c\\d'), ('\\\\a\\b', '\\', 'c\\d'))
155        # These are non-UNC paths (according to ntpath.py and test_ntpath).
156        # However, command.com says such paths are invalid, so it's
157        # difficult to know what the right semantics are.
158        self.assertEqual(f('\\\\\\a\\b'), ('', '\\', 'a\\b'))
159        self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
160
161
162#
163# Tests for the pure classes.
164#
165
166class _BasePurePathTest(object):
167
168    # Keys are canonical paths, values are list of tuples of arguments
169    # supposed to produce equal paths.
170    equivalences = {
171        'a/b': [
172            ('a', 'b'), ('a/', 'b'), ('a', 'b/'), ('a/', 'b/'),
173            ('a/b/',), ('a//b',), ('a//b//',),
174            # Empty components get removed.
175            ('', 'a', 'b'), ('a', '', 'b'), ('a', 'b', ''),
176            ],
177        '/b/c/d': [
178            ('a', '/b/c', 'd'), ('a', '///b//c', 'd/'),
179            ('/a', '/b/c', 'd'),
180            # Empty components get removed.
181            ('/', 'b', '', 'c/d'), ('/', '', 'b/c/d'), ('', '/b/c/d'),
182            ],
183    }
184
185    def setUp(self):
186        p = self.cls('a')
187        self.flavour = p._flavour
188        self.sep = self.flavour.sep
189        self.altsep = self.flavour.altsep
190
191    def test_constructor_common(self):
192        P = self.cls
193        p = P('a')
194        self.assertIsInstance(p, P)
195        P('a', 'b', 'c')
196        P('/a', 'b', 'c')
197        P('a/b/c')
198        P('/a/b/c')
199        P(FakePath("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        self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c")))
204
205    def _check_str_subclass(self, *args):
206        # Issue #21127: it should be possible to construct a PurePath object
207        # from a str subclass instance, and it then gets converted to
208        # a pure str object.
209        class StrSubclass(str):
210            pass
211        P = self.cls
212        p = P(*(StrSubclass(x) for x in args))
213        self.assertEqual(p, P(*args))
214        for part in p.parts:
215            self.assertIs(type(part), str)
216
217    def test_str_subclass_common(self):
218        self._check_str_subclass('')
219        self._check_str_subclass('.')
220        self._check_str_subclass('a')
221        self._check_str_subclass('a/b.txt')
222        self._check_str_subclass('/a/b.txt')
223
224    def test_join_common(self):
225        P = self.cls
226        p = P('a/b')
227        pp = p.joinpath('c')
228        self.assertEqual(pp, P('a/b/c'))
229        self.assertIs(type(pp), type(p))
230        pp = p.joinpath('c', 'd')
231        self.assertEqual(pp, P('a/b/c/d'))
232        pp = p.joinpath(P('c'))
233        self.assertEqual(pp, P('a/b/c'))
234        pp = p.joinpath('/c')
235        self.assertEqual(pp, P('/c'))
236
237    def test_div_common(self):
238        # Basically the same as joinpath().
239        P = self.cls
240        p = P('a/b')
241        pp = p / 'c'
242        self.assertEqual(pp, P('a/b/c'))
243        self.assertIs(type(pp), type(p))
244        pp = p / 'c/d'
245        self.assertEqual(pp, P('a/b/c/d'))
246        pp = p / 'c' / 'd'
247        self.assertEqual(pp, P('a/b/c/d'))
248        pp = 'c' / p / 'd'
249        self.assertEqual(pp, P('c/a/b/d'))
250        pp = p / P('c')
251        self.assertEqual(pp, P('a/b/c'))
252        pp = p/ '/c'
253        self.assertEqual(pp, P('/c'))
254
255    def _check_str(self, expected, args):
256        p = self.cls(*args)
257        self.assertEqual(str(p), expected.replace('/', self.sep))
258
259    def test_str_common(self):
260        # Canonicalized paths roundtrip.
261        for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
262            self._check_str(pathstr, (pathstr,))
263        # Special case for the empty path.
264        self._check_str('.', ('',))
265        # Other tests for str() are in test_equivalences().
266
267    def test_as_posix_common(self):
268        P = self.cls
269        for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
270            self.assertEqual(P(pathstr).as_posix(), pathstr)
271        # Other tests for as_posix() are in test_equivalences().
272
273    def test_as_bytes_common(self):
274        sep = os.fsencode(self.sep)
275        P = self.cls
276        self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b')
277
278    def test_as_uri_common(self):
279        P = self.cls
280        with self.assertRaises(ValueError):
281            P('a').as_uri()
282        with self.assertRaises(ValueError):
283            P().as_uri()
284
285    def test_repr_common(self):
286        for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
287            p = self.cls(pathstr)
288            clsname = p.__class__.__name__
289            r = repr(p)
290            # The repr() is in the form ClassName("forward-slashes path").
291            self.assertTrue(r.startswith(clsname + '('), r)
292            self.assertTrue(r.endswith(')'), r)
293            inner = r[len(clsname) + 1 : -1]
294            self.assertEqual(eval(inner), p.as_posix())
295            # The repr() roundtrips.
296            q = eval(r, pathlib.__dict__)
297            self.assertIs(q.__class__, p.__class__)
298            self.assertEqual(q, p)
299            self.assertEqual(repr(q), r)
300
301    def test_eq_common(self):
302        P = self.cls
303        self.assertEqual(P('a/b'), P('a/b'))
304        self.assertEqual(P('a/b'), P('a', 'b'))
305        self.assertNotEqual(P('a/b'), P('a'))
306        self.assertNotEqual(P('a/b'), P('/a/b'))
307        self.assertNotEqual(P('a/b'), P())
308        self.assertNotEqual(P('/a/b'), P('/'))
309        self.assertNotEqual(P(), P('/'))
310        self.assertNotEqual(P(), "")
311        self.assertNotEqual(P(), {})
312        self.assertNotEqual(P(), int)
313
314    def test_match_common(self):
315        P = self.cls
316        self.assertRaises(ValueError, P('a').match, '')
317        self.assertRaises(ValueError, P('a').match, '.')
318        # Simple relative pattern.
319        self.assertTrue(P('b.py').match('b.py'))
320        self.assertTrue(P('a/b.py').match('b.py'))
321        self.assertTrue(P('/a/b.py').match('b.py'))
322        self.assertFalse(P('a.py').match('b.py'))
323        self.assertFalse(P('b/py').match('b.py'))
324        self.assertFalse(P('/a.py').match('b.py'))
325        self.assertFalse(P('b.py/c').match('b.py'))
326        # Wilcard relative pattern.
327        self.assertTrue(P('b.py').match('*.py'))
328        self.assertTrue(P('a/b.py').match('*.py'))
329        self.assertTrue(P('/a/b.py').match('*.py'))
330        self.assertFalse(P('b.pyc').match('*.py'))
331        self.assertFalse(P('b./py').match('*.py'))
332        self.assertFalse(P('b.py/c').match('*.py'))
333        # Multi-part relative pattern.
334        self.assertTrue(P('ab/c.py').match('a*/*.py'))
335        self.assertTrue(P('/d/ab/c.py').match('a*/*.py'))
336        self.assertFalse(P('a.py').match('a*/*.py'))
337        self.assertFalse(P('/dab/c.py').match('a*/*.py'))
338        self.assertFalse(P('ab/c.py/d').match('a*/*.py'))
339        # Absolute pattern.
340        self.assertTrue(P('/b.py').match('/*.py'))
341        self.assertFalse(P('b.py').match('/*.py'))
342        self.assertFalse(P('a/b.py').match('/*.py'))
343        self.assertFalse(P('/a/b.py').match('/*.py'))
344        # Multi-part absolute pattern.
345        self.assertTrue(P('/a/b.py').match('/a/*.py'))
346        self.assertFalse(P('/ab.py').match('/a/*.py'))
347        self.assertFalse(P('/a/b/c.py').match('/a/*.py'))
348        # Multi-part glob-style pattern.
349        self.assertFalse(P('/a/b/c.py').match('/**/*.py'))
350        self.assertTrue(P('/a/b/c.py').match('/a/**/*.py'))
351
352    def test_ordering_common(self):
353        # Ordering is tuple-alike.
354        def assertLess(a, b):
355            self.assertLess(a, b)
356            self.assertGreater(b, a)
357        P = self.cls
358        a = P('a')
359        b = P('a/b')
360        c = P('abc')
361        d = P('b')
362        assertLess(a, b)
363        assertLess(a, c)
364        assertLess(a, d)
365        assertLess(b, c)
366        assertLess(c, d)
367        P = self.cls
368        a = P('/a')
369        b = P('/a/b')
370        c = P('/abc')
371        d = P('/b')
372        assertLess(a, b)
373        assertLess(a, c)
374        assertLess(a, d)
375        assertLess(b, c)
376        assertLess(c, d)
377        with self.assertRaises(TypeError):
378            P() < {}
379
380    def test_parts_common(self):
381        # `parts` returns a tuple.
382        sep = self.sep
383        P = self.cls
384        p = P('a/b')
385        parts = p.parts
386        self.assertEqual(parts, ('a', 'b'))
387        # The object gets reused.
388        self.assertIs(parts, p.parts)
389        # When the path is absolute, the anchor is a separate part.
390        p = P('/a/b')
391        parts = p.parts
392        self.assertEqual(parts, (sep, 'a', 'b'))
393
394    def test_fspath_common(self):
395        P = self.cls
396        p = P('a/b')
397        self._check_str(p.__fspath__(), ('a/b',))
398        self._check_str(os.fspath(p), ('a/b',))
399
400    def test_equivalences(self):
401        for k, tuples in self.equivalences.items():
402            canon = k.replace('/', self.sep)
403            posix = k.replace(self.sep, '/')
404            if canon != posix:
405                tuples = tuples + [
406                    tuple(part.replace('/', self.sep) for part in t)
407                    for t in tuples
408                    ]
409                tuples.append((posix, ))
410            pcanon = self.cls(canon)
411            for t in tuples:
412                p = self.cls(*t)
413                self.assertEqual(p, pcanon, "failed with args {}".format(t))
414                self.assertEqual(hash(p), hash(pcanon))
415                self.assertEqual(str(p), canon)
416                self.assertEqual(p.as_posix(), posix)
417
418    def test_parent_common(self):
419        # Relative
420        P = self.cls
421        p = P('a/b/c')
422        self.assertEqual(p.parent, P('a/b'))
423        self.assertEqual(p.parent.parent, P('a'))
424        self.assertEqual(p.parent.parent.parent, P())
425        self.assertEqual(p.parent.parent.parent.parent, P())
426        # Anchored
427        p = P('/a/b/c')
428        self.assertEqual(p.parent, P('/a/b'))
429        self.assertEqual(p.parent.parent, P('/a'))
430        self.assertEqual(p.parent.parent.parent, P('/'))
431        self.assertEqual(p.parent.parent.parent.parent, P('/'))
432
433    def test_parents_common(self):
434        # Relative
435        P = self.cls
436        p = P('a/b/c')
437        par = p.parents
438        self.assertEqual(len(par), 3)
439        self.assertEqual(par[0], P('a/b'))
440        self.assertEqual(par[1], P('a'))
441        self.assertEqual(par[2], P('.'))
442        self.assertEqual(list(par), [P('a/b'), P('a'), P('.')])
443        with self.assertRaises(IndexError):
444            par[-1]
445        with self.assertRaises(IndexError):
446            par[3]
447        with self.assertRaises(TypeError):
448            par[0] = p
449        # Anchored
450        p = P('/a/b/c')
451        par = p.parents
452        self.assertEqual(len(par), 3)
453        self.assertEqual(par[0], P('/a/b'))
454        self.assertEqual(par[1], P('/a'))
455        self.assertEqual(par[2], P('/'))
456        self.assertEqual(list(par), [P('/a/b'), P('/a'), P('/')])
457        with self.assertRaises(IndexError):
458            par[3]
459
460    def test_drive_common(self):
461        P = self.cls
462        self.assertEqual(P('a/b').drive, '')
463        self.assertEqual(P('/a/b').drive, '')
464        self.assertEqual(P('').drive, '')
465
466    def test_root_common(self):
467        P = self.cls
468        sep = self.sep
469        self.assertEqual(P('').root, '')
470        self.assertEqual(P('a/b').root, '')
471        self.assertEqual(P('/').root, sep)
472        self.assertEqual(P('/a/b').root, sep)
473
474    def test_anchor_common(self):
475        P = self.cls
476        sep = self.sep
477        self.assertEqual(P('').anchor, '')
478        self.assertEqual(P('a/b').anchor, '')
479        self.assertEqual(P('/').anchor, sep)
480        self.assertEqual(P('/a/b').anchor, sep)
481
482    def test_name_common(self):
483        P = self.cls
484        self.assertEqual(P('').name, '')
485        self.assertEqual(P('.').name, '')
486        self.assertEqual(P('/').name, '')
487        self.assertEqual(P('a/b').name, 'b')
488        self.assertEqual(P('/a/b').name, 'b')
489        self.assertEqual(P('/a/b/.').name, 'b')
490        self.assertEqual(P('a/b.py').name, 'b.py')
491        self.assertEqual(P('/a/b.py').name, 'b.py')
492
493    def test_suffix_common(self):
494        P = self.cls
495        self.assertEqual(P('').suffix, '')
496        self.assertEqual(P('.').suffix, '')
497        self.assertEqual(P('..').suffix, '')
498        self.assertEqual(P('/').suffix, '')
499        self.assertEqual(P('a/b').suffix, '')
500        self.assertEqual(P('/a/b').suffix, '')
501        self.assertEqual(P('/a/b/.').suffix, '')
502        self.assertEqual(P('a/b.py').suffix, '.py')
503        self.assertEqual(P('/a/b.py').suffix, '.py')
504        self.assertEqual(P('a/.hgrc').suffix, '')
505        self.assertEqual(P('/a/.hgrc').suffix, '')
506        self.assertEqual(P('a/.hg.rc').suffix, '.rc')
507        self.assertEqual(P('/a/.hg.rc').suffix, '.rc')
508        self.assertEqual(P('a/b.tar.gz').suffix, '.gz')
509        self.assertEqual(P('/a/b.tar.gz').suffix, '.gz')
510        self.assertEqual(P('a/Some name. Ending with a dot.').suffix, '')
511        self.assertEqual(P('/a/Some name. Ending with a dot.').suffix, '')
512
513    def test_suffixes_common(self):
514        P = self.cls
515        self.assertEqual(P('').suffixes, [])
516        self.assertEqual(P('.').suffixes, [])
517        self.assertEqual(P('/').suffixes, [])
518        self.assertEqual(P('a/b').suffixes, [])
519        self.assertEqual(P('/a/b').suffixes, [])
520        self.assertEqual(P('/a/b/.').suffixes, [])
521        self.assertEqual(P('a/b.py').suffixes, ['.py'])
522        self.assertEqual(P('/a/b.py').suffixes, ['.py'])
523        self.assertEqual(P('a/.hgrc').suffixes, [])
524        self.assertEqual(P('/a/.hgrc').suffixes, [])
525        self.assertEqual(P('a/.hg.rc').suffixes, ['.rc'])
526        self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc'])
527        self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz'])
528        self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz'])
529        self.assertEqual(P('a/Some name. Ending with a dot.').suffixes, [])
530        self.assertEqual(P('/a/Some name. Ending with a dot.').suffixes, [])
531
532    def test_stem_common(self):
533        P = self.cls
534        self.assertEqual(P('').stem, '')
535        self.assertEqual(P('.').stem, '')
536        self.assertEqual(P('..').stem, '..')
537        self.assertEqual(P('/').stem, '')
538        self.assertEqual(P('a/b').stem, 'b')
539        self.assertEqual(P('a/b.py').stem, 'b')
540        self.assertEqual(P('a/.hgrc').stem, '.hgrc')
541        self.assertEqual(P('a/.hg.rc').stem, '.hg')
542        self.assertEqual(P('a/b.tar.gz').stem, 'b.tar')
543        self.assertEqual(P('a/Some name. Ending with a dot.').stem,
544                         'Some name. Ending with a dot.')
545
546    def test_with_name_common(self):
547        P = self.cls
548        self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml'))
549        self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml'))
550        self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml'))
551        self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml'))
552        self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml'))
553        self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml'))
554        self.assertRaises(ValueError, P('').with_name, 'd.xml')
555        self.assertRaises(ValueError, P('.').with_name, 'd.xml')
556        self.assertRaises(ValueError, P('/').with_name, 'd.xml')
557        self.assertRaises(ValueError, P('a/b').with_name, '')
558        self.assertRaises(ValueError, P('a/b').with_name, '/c')
559        self.assertRaises(ValueError, P('a/b').with_name, 'c/')
560        self.assertRaises(ValueError, P('a/b').with_name, 'c/d')
561
562    def test_with_suffix_common(self):
563        P = self.cls
564        self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz'))
565        self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz'))
566        self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz'))
567        self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz'))
568        # Stripping suffix.
569        self.assertEqual(P('a/b.py').with_suffix(''), P('a/b'))
570        self.assertEqual(P('/a/b').with_suffix(''), P('/a/b'))
571        # Path doesn't have a "filename" component.
572        self.assertRaises(ValueError, P('').with_suffix, '.gz')
573        self.assertRaises(ValueError, P('.').with_suffix, '.gz')
574        self.assertRaises(ValueError, P('/').with_suffix, '.gz')
575        # Invalid suffix.
576        self.assertRaises(ValueError, P('a/b').with_suffix, 'gz')
577        self.assertRaises(ValueError, P('a/b').with_suffix, '/')
578        self.assertRaises(ValueError, P('a/b').with_suffix, '.')
579        self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz')
580        self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d')
581        self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
582        self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
583        self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
584        self.assertRaises(ValueError, P('a/b').with_suffix,
585                          (self.flavour.sep, 'd'))
586
587    def test_relative_to_common(self):
588        P = self.cls
589        p = P('a/b')
590        self.assertRaises(TypeError, p.relative_to)
591        self.assertRaises(TypeError, p.relative_to, b'a')
592        self.assertEqual(p.relative_to(P()), P('a/b'))
593        self.assertEqual(p.relative_to(''), P('a/b'))
594        self.assertEqual(p.relative_to(P('a')), P('b'))
595        self.assertEqual(p.relative_to('a'), P('b'))
596        self.assertEqual(p.relative_to('a/'), P('b'))
597        self.assertEqual(p.relative_to(P('a/b')), P())
598        self.assertEqual(p.relative_to('a/b'), P())
599        # With several args.
600        self.assertEqual(p.relative_to('a', 'b'), P())
601        # Unrelated paths.
602        self.assertRaises(ValueError, p.relative_to, P('c'))
603        self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
604        self.assertRaises(ValueError, p.relative_to, P('a/c'))
605        self.assertRaises(ValueError, p.relative_to, P('/a'))
606        p = P('/a/b')
607        self.assertEqual(p.relative_to(P('/')), P('a/b'))
608        self.assertEqual(p.relative_to('/'), P('a/b'))
609        self.assertEqual(p.relative_to(P('/a')), P('b'))
610        self.assertEqual(p.relative_to('/a'), P('b'))
611        self.assertEqual(p.relative_to('/a/'), P('b'))
612        self.assertEqual(p.relative_to(P('/a/b')), P())
613        self.assertEqual(p.relative_to('/a/b'), P())
614        # Unrelated paths.
615        self.assertRaises(ValueError, p.relative_to, P('/c'))
616        self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
617        self.assertRaises(ValueError, p.relative_to, P('/a/c'))
618        self.assertRaises(ValueError, p.relative_to, P())
619        self.assertRaises(ValueError, p.relative_to, '')
620        self.assertRaises(ValueError, p.relative_to, P('a'))
621
622    def test_pickling_common(self):
623        P = self.cls
624        p = P('/a/b')
625        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
626            dumped = pickle.dumps(p, proto)
627            pp = pickle.loads(dumped)
628            self.assertIs(pp.__class__, p.__class__)
629            self.assertEqual(pp, p)
630            self.assertEqual(hash(pp), hash(p))
631            self.assertEqual(str(pp), str(p))
632
633
634class PurePosixPathTest(_BasePurePathTest, unittest.TestCase):
635    cls = pathlib.PurePosixPath
636
637    def test_root(self):
638        P = self.cls
639        self.assertEqual(P('/a/b').root, '/')
640        self.assertEqual(P('///a/b').root, '/')
641        # POSIX special case for two leading slashes.
642        self.assertEqual(P('//a/b').root, '//')
643
644    def test_eq(self):
645        P = self.cls
646        self.assertNotEqual(P('a/b'), P('A/b'))
647        self.assertEqual(P('/a'), P('///a'))
648        self.assertNotEqual(P('/a'), P('//a'))
649
650    def test_as_uri(self):
651        P = self.cls
652        self.assertEqual(P('/').as_uri(), 'file:///')
653        self.assertEqual(P('/a/b.c').as_uri(), 'file:///a/b.c')
654        self.assertEqual(P('/a/b%#c').as_uri(), 'file:///a/b%25%23c')
655
656    def test_as_uri_non_ascii(self):
657        from urllib.parse import quote_from_bytes
658        P = self.cls
659        try:
660            os.fsencode('\xe9')
661        except UnicodeEncodeError:
662            self.skipTest("\\xe9 cannot be encoded to the filesystem encoding")
663        self.assertEqual(P('/a/b\xe9').as_uri(),
664                         'file:///a/b' + quote_from_bytes(os.fsencode('\xe9')))
665
666    def test_match(self):
667        P = self.cls
668        self.assertFalse(P('A.py').match('a.PY'))
669
670    def test_is_absolute(self):
671        P = self.cls
672        self.assertFalse(P().is_absolute())
673        self.assertFalse(P('a').is_absolute())
674        self.assertFalse(P('a/b/').is_absolute())
675        self.assertTrue(P('/').is_absolute())
676        self.assertTrue(P('/a').is_absolute())
677        self.assertTrue(P('/a/b/').is_absolute())
678        self.assertTrue(P('//a').is_absolute())
679        self.assertTrue(P('//a/b').is_absolute())
680
681    def test_is_reserved(self):
682        P = self.cls
683        self.assertIs(False, P('').is_reserved())
684        self.assertIs(False, P('/').is_reserved())
685        self.assertIs(False, P('/foo/bar').is_reserved())
686        self.assertIs(False, P('/dev/con/PRN/NUL').is_reserved())
687
688    def test_join(self):
689        P = self.cls
690        p = P('//a')
691        pp = p.joinpath('b')
692        self.assertEqual(pp, P('//a/b'))
693        pp = P('/a').joinpath('//c')
694        self.assertEqual(pp, P('//c'))
695        pp = P('//a').joinpath('/c')
696        self.assertEqual(pp, P('/c'))
697
698    def test_div(self):
699        # Basically the same as joinpath().
700        P = self.cls
701        p = P('//a')
702        pp = p / 'b'
703        self.assertEqual(pp, P('//a/b'))
704        pp = P('/a') / '//c'
705        self.assertEqual(pp, P('//c'))
706        pp = P('//a') / '/c'
707        self.assertEqual(pp, P('/c'))
708
709
710class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
711    cls = pathlib.PureWindowsPath
712
713    equivalences = _BasePurePathTest.equivalences.copy()
714    equivalences.update({
715        'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('/', 'c:', 'a') ],
716        'c:/a': [
717            ('c:/', 'a'), ('c:', '/', 'a'), ('c:', '/a'),
718            ('/z', 'c:/', 'a'), ('//x/y', 'c:/', 'a'),
719            ],
720        '//a/b/': [ ('//a/b',) ],
721        '//a/b/c': [
722            ('//a/b', 'c'), ('//a/b/', 'c'),
723            ],
724    })
725
726    def test_str(self):
727        p = self.cls('a/b/c')
728        self.assertEqual(str(p), 'a\\b\\c')
729        p = self.cls('c:/a/b/c')
730        self.assertEqual(str(p), 'c:\\a\\b\\c')
731        p = self.cls('//a/b')
732        self.assertEqual(str(p), '\\\\a\\b\\')
733        p = self.cls('//a/b/c')
734        self.assertEqual(str(p), '\\\\a\\b\\c')
735        p = self.cls('//a/b/c/d')
736        self.assertEqual(str(p), '\\\\a\\b\\c\\d')
737
738    def test_str_subclass(self):
739        self._check_str_subclass('c:')
740        self._check_str_subclass('c:a')
741        self._check_str_subclass('c:a\\b.txt')
742        self._check_str_subclass('c:\\')
743        self._check_str_subclass('c:\\a')
744        self._check_str_subclass('c:\\a\\b.txt')
745        self._check_str_subclass('\\\\some\\share')
746        self._check_str_subclass('\\\\some\\share\\a')
747        self._check_str_subclass('\\\\some\\share\\a\\b.txt')
748
749    def test_eq(self):
750        P = self.cls
751        self.assertEqual(P('c:a/b'), P('c:a/b'))
752        self.assertEqual(P('c:a/b'), P('c:', 'a', 'b'))
753        self.assertNotEqual(P('c:a/b'), P('d:a/b'))
754        self.assertNotEqual(P('c:a/b'), P('c:/a/b'))
755        self.assertNotEqual(P('/a/b'), P('c:/a/b'))
756        # Case-insensitivity.
757        self.assertEqual(P('a/B'), P('A/b'))
758        self.assertEqual(P('C:a/B'), P('c:A/b'))
759        self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b'))
760
761    def test_as_uri(self):
762        P = self.cls
763        with self.assertRaises(ValueError):
764            P('/a/b').as_uri()
765        with self.assertRaises(ValueError):
766            P('c:a/b').as_uri()
767        self.assertEqual(P('c:/').as_uri(), 'file:///c:/')
768        self.assertEqual(P('c:/a/b.c').as_uri(), 'file:///c:/a/b.c')
769        self.assertEqual(P('c:/a/b%#c').as_uri(), 'file:///c:/a/b%25%23c')
770        self.assertEqual(P('c:/a/b\xe9').as_uri(), 'file:///c:/a/b%C3%A9')
771        self.assertEqual(P('//some/share/').as_uri(), 'file://some/share/')
772        self.assertEqual(P('//some/share/a/b.c').as_uri(),
773                         'file://some/share/a/b.c')
774        self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(),
775                         'file://some/share/a/b%25%23c%C3%A9')
776
777    def test_match_common(self):
778        P = self.cls
779        # Absolute patterns.
780        self.assertTrue(P('c:/b.py').match('/*.py'))
781        self.assertTrue(P('c:/b.py').match('c:*.py'))
782        self.assertTrue(P('c:/b.py').match('c:/*.py'))
783        self.assertFalse(P('d:/b.py').match('c:/*.py'))  # wrong drive
784        self.assertFalse(P('b.py').match('/*.py'))
785        self.assertFalse(P('b.py').match('c:*.py'))
786        self.assertFalse(P('b.py').match('c:/*.py'))
787        self.assertFalse(P('c:b.py').match('/*.py'))
788        self.assertFalse(P('c:b.py').match('c:/*.py'))
789        self.assertFalse(P('/b.py').match('c:*.py'))
790        self.assertFalse(P('/b.py').match('c:/*.py'))
791        # UNC patterns.
792        self.assertTrue(P('//some/share/a.py').match('/*.py'))
793        self.assertTrue(P('//some/share/a.py').match('//some/share/*.py'))
794        self.assertFalse(P('//other/share/a.py').match('//some/share/*.py'))
795        self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py'))
796        # Case-insensitivity.
797        self.assertTrue(P('B.py').match('b.PY'))
798        self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY'))
799        self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY'))
800
801    def test_ordering_common(self):
802        # Case-insensitivity.
803        def assertOrderedEqual(a, b):
804            self.assertLessEqual(a, b)
805            self.assertGreaterEqual(b, a)
806        P = self.cls
807        p = P('c:A/b')
808        q = P('C:a/B')
809        assertOrderedEqual(p, q)
810        self.assertFalse(p < q)
811        self.assertFalse(p > q)
812        p = P('//some/Share/A/b')
813        q = P('//Some/SHARE/a/B')
814        assertOrderedEqual(p, q)
815        self.assertFalse(p < q)
816        self.assertFalse(p > q)
817
818    def test_parts(self):
819        P = self.cls
820        p = P('c:a/b')
821        parts = p.parts
822        self.assertEqual(parts, ('c:', 'a', 'b'))
823        p = P('c:/a/b')
824        parts = p.parts
825        self.assertEqual(parts, ('c:\\', 'a', 'b'))
826        p = P('//a/b/c/d')
827        parts = p.parts
828        self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
829
830    def test_parent(self):
831        # Anchored
832        P = self.cls
833        p = P('z:a/b/c')
834        self.assertEqual(p.parent, P('z:a/b'))
835        self.assertEqual(p.parent.parent, P('z:a'))
836        self.assertEqual(p.parent.parent.parent, P('z:'))
837        self.assertEqual(p.parent.parent.parent.parent, P('z:'))
838        p = P('z:/a/b/c')
839        self.assertEqual(p.parent, P('z:/a/b'))
840        self.assertEqual(p.parent.parent, P('z:/a'))
841        self.assertEqual(p.parent.parent.parent, P('z:/'))
842        self.assertEqual(p.parent.parent.parent.parent, P('z:/'))
843        p = P('//a/b/c/d')
844        self.assertEqual(p.parent, P('//a/b/c'))
845        self.assertEqual(p.parent.parent, P('//a/b'))
846        self.assertEqual(p.parent.parent.parent, P('//a/b'))
847
848    def test_parents(self):
849        # Anchored
850        P = self.cls
851        p = P('z:a/b/')
852        par = p.parents
853        self.assertEqual(len(par), 2)
854        self.assertEqual(par[0], P('z:a'))
855        self.assertEqual(par[1], P('z:'))
856        self.assertEqual(list(par), [P('z:a'), P('z:')])
857        with self.assertRaises(IndexError):
858            par[2]
859        p = P('z:/a/b/')
860        par = p.parents
861        self.assertEqual(len(par), 2)
862        self.assertEqual(par[0], P('z:/a'))
863        self.assertEqual(par[1], P('z:/'))
864        self.assertEqual(list(par), [P('z:/a'), P('z:/')])
865        with self.assertRaises(IndexError):
866            par[2]
867        p = P('//a/b/c/d')
868        par = p.parents
869        self.assertEqual(len(par), 2)
870        self.assertEqual(par[0], P('//a/b/c'))
871        self.assertEqual(par[1], P('//a/b'))
872        self.assertEqual(list(par), [P('//a/b/c'), P('//a/b')])
873        with self.assertRaises(IndexError):
874            par[2]
875
876    def test_drive(self):
877        P = self.cls
878        self.assertEqual(P('c:').drive, 'c:')
879        self.assertEqual(P('c:a/b').drive, 'c:')
880        self.assertEqual(P('c:/').drive, 'c:')
881        self.assertEqual(P('c:/a/b/').drive, 'c:')
882        self.assertEqual(P('//a/b').drive, '\\\\a\\b')
883        self.assertEqual(P('//a/b/').drive, '\\\\a\\b')
884        self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b')
885
886    def test_root(self):
887        P = self.cls
888        self.assertEqual(P('c:').root, '')
889        self.assertEqual(P('c:a/b').root, '')
890        self.assertEqual(P('c:/').root, '\\')
891        self.assertEqual(P('c:/a/b/').root, '\\')
892        self.assertEqual(P('//a/b').root, '\\')
893        self.assertEqual(P('//a/b/').root, '\\')
894        self.assertEqual(P('//a/b/c/d').root, '\\')
895
896    def test_anchor(self):
897        P = self.cls
898        self.assertEqual(P('c:').anchor, 'c:')
899        self.assertEqual(P('c:a/b').anchor, 'c:')
900        self.assertEqual(P('c:/').anchor, 'c:\\')
901        self.assertEqual(P('c:/a/b/').anchor, 'c:\\')
902        self.assertEqual(P('//a/b').anchor, '\\\\a\\b\\')
903        self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\')
904        self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\')
905
906    def test_name(self):
907        P = self.cls
908        self.assertEqual(P('c:').name, '')
909        self.assertEqual(P('c:/').name, '')
910        self.assertEqual(P('c:a/b').name, 'b')
911        self.assertEqual(P('c:/a/b').name, 'b')
912        self.assertEqual(P('c:a/b.py').name, 'b.py')
913        self.assertEqual(P('c:/a/b.py').name, 'b.py')
914        self.assertEqual(P('//My.py/Share.php').name, '')
915        self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
916
917    def test_suffix(self):
918        P = self.cls
919        self.assertEqual(P('c:').suffix, '')
920        self.assertEqual(P('c:/').suffix, '')
921        self.assertEqual(P('c:a/b').suffix, '')
922        self.assertEqual(P('c:/a/b').suffix, '')
923        self.assertEqual(P('c:a/b.py').suffix, '.py')
924        self.assertEqual(P('c:/a/b.py').suffix, '.py')
925        self.assertEqual(P('c:a/.hgrc').suffix, '')
926        self.assertEqual(P('c:/a/.hgrc').suffix, '')
927        self.assertEqual(P('c:a/.hg.rc').suffix, '.rc')
928        self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc')
929        self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz')
930        self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz')
931        self.assertEqual(P('c:a/Some name. Ending with a dot.').suffix, '')
932        self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffix, '')
933        self.assertEqual(P('//My.py/Share.php').suffix, '')
934        self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
935
936    def test_suffixes(self):
937        P = self.cls
938        self.assertEqual(P('c:').suffixes, [])
939        self.assertEqual(P('c:/').suffixes, [])
940        self.assertEqual(P('c:a/b').suffixes, [])
941        self.assertEqual(P('c:/a/b').suffixes, [])
942        self.assertEqual(P('c:a/b.py').suffixes, ['.py'])
943        self.assertEqual(P('c:/a/b.py').suffixes, ['.py'])
944        self.assertEqual(P('c:a/.hgrc').suffixes, [])
945        self.assertEqual(P('c:/a/.hgrc').suffixes, [])
946        self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc'])
947        self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc'])
948        self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz'])
949        self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz'])
950        self.assertEqual(P('//My.py/Share.php').suffixes, [])
951        self.assertEqual(P('//My.py/Share.php/a/b').suffixes, [])
952        self.assertEqual(P('c:a/Some name. Ending with a dot.').suffixes, [])
953        self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffixes, [])
954
955    def test_stem(self):
956        P = self.cls
957        self.assertEqual(P('c:').stem, '')
958        self.assertEqual(P('c:.').stem, '')
959        self.assertEqual(P('c:..').stem, '..')
960        self.assertEqual(P('c:/').stem, '')
961        self.assertEqual(P('c:a/b').stem, 'b')
962        self.assertEqual(P('c:a/b.py').stem, 'b')
963        self.assertEqual(P('c:a/.hgrc').stem, '.hgrc')
964        self.assertEqual(P('c:a/.hg.rc').stem, '.hg')
965        self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
966        self.assertEqual(P('c:a/Some name. Ending with a dot.').stem,
967                         'Some name. Ending with a dot.')
968
969    def test_with_name(self):
970        P = self.cls
971        self.assertEqual(P('c:a/b').with_name('d.xml'), P('c:a/d.xml'))
972        self.assertEqual(P('c:/a/b').with_name('d.xml'), P('c:/a/d.xml'))
973        self.assertEqual(P('c:a/Dot ending.').with_name('d.xml'), P('c:a/d.xml'))
974        self.assertEqual(P('c:/a/Dot ending.').with_name('d.xml'), P('c:/a/d.xml'))
975        self.assertRaises(ValueError, P('c:').with_name, 'd.xml')
976        self.assertRaises(ValueError, P('c:/').with_name, 'd.xml')
977        self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml')
978        self.assertRaises(ValueError, P('c:a/b').with_name, 'd:')
979        self.assertRaises(ValueError, P('c:a/b').with_name, 'd:e')
980        self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e')
981        self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share')
982
983    def test_with_suffix(self):
984        P = self.cls
985        self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz'))
986        self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz'))
987        self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz'))
988        self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz'))
989        # Path doesn't have a "filename" component.
990        self.assertRaises(ValueError, P('').with_suffix, '.gz')
991        self.assertRaises(ValueError, P('.').with_suffix, '.gz')
992        self.assertRaises(ValueError, P('/').with_suffix, '.gz')
993        self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz')
994        # Invalid suffix.
995        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz')
996        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/')
997        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\')
998        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:')
999        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz')
1000        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz')
1001        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz')
1002        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d')
1003        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d')
1004        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d')
1005        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
1006
1007    def test_relative_to(self):
1008        P = self.cls
1009        p = P('C:Foo/Bar')
1010        self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar'))
1011        self.assertEqual(p.relative_to('c:'), P('Foo/Bar'))
1012        self.assertEqual(p.relative_to(P('c:foO')), P('Bar'))
1013        self.assertEqual(p.relative_to('c:foO'), P('Bar'))
1014        self.assertEqual(p.relative_to('c:foO/'), P('Bar'))
1015        self.assertEqual(p.relative_to(P('c:foO/baR')), P())
1016        self.assertEqual(p.relative_to('c:foO/baR'), P())
1017        # Unrelated paths.
1018        self.assertRaises(ValueError, p.relative_to, P())
1019        self.assertRaises(ValueError, p.relative_to, '')
1020        self.assertRaises(ValueError, p.relative_to, P('d:'))
1021        self.assertRaises(ValueError, p.relative_to, P('/'))
1022        self.assertRaises(ValueError, p.relative_to, P('Foo'))
1023        self.assertRaises(ValueError, p.relative_to, P('/Foo'))
1024        self.assertRaises(ValueError, p.relative_to, P('C:/Foo'))
1025        self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz'))
1026        self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz'))
1027        p = P('C:/Foo/Bar')
1028        self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar'))
1029        self.assertEqual(p.relative_to('c:'), P('/Foo/Bar'))
1030        self.assertEqual(str(p.relative_to(P('c:'))), '\\Foo\\Bar')
1031        self.assertEqual(str(p.relative_to('c:')), '\\Foo\\Bar')
1032        self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar'))
1033        self.assertEqual(p.relative_to('c:/'), P('Foo/Bar'))
1034        self.assertEqual(p.relative_to(P('c:/foO')), P('Bar'))
1035        self.assertEqual(p.relative_to('c:/foO'), P('Bar'))
1036        self.assertEqual(p.relative_to('c:/foO/'), P('Bar'))
1037        self.assertEqual(p.relative_to(P('c:/foO/baR')), P())
1038        self.assertEqual(p.relative_to('c:/foO/baR'), P())
1039        # Unrelated paths.
1040        self.assertRaises(ValueError, p.relative_to, P('C:/Baz'))
1041        self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz'))
1042        self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz'))
1043        self.assertRaises(ValueError, p.relative_to, P('C:Foo'))
1044        self.assertRaises(ValueError, p.relative_to, P('d:'))
1045        self.assertRaises(ValueError, p.relative_to, P('d:/'))
1046        self.assertRaises(ValueError, p.relative_to, P('/'))
1047        self.assertRaises(ValueError, p.relative_to, P('/Foo'))
1048        self.assertRaises(ValueError, p.relative_to, P('//C/Foo'))
1049        # UNC paths.
1050        p = P('//Server/Share/Foo/Bar')
1051        self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar'))
1052        self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar'))
1053        self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar'))
1054        self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar'))
1055        self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar'))
1056        self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar'))
1057        self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P())
1058        self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P())
1059        # Unrelated paths.
1060        self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'))
1061        self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'))
1062        self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'))
1063        self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'))
1064
1065    def test_is_absolute(self):
1066        P = self.cls
1067        # Under NT, only paths with both a drive and a root are absolute.
1068        self.assertFalse(P().is_absolute())
1069        self.assertFalse(P('a').is_absolute())
1070        self.assertFalse(P('a/b/').is_absolute())
1071        self.assertFalse(P('/').is_absolute())
1072        self.assertFalse(P('/a').is_absolute())
1073        self.assertFalse(P('/a/b/').is_absolute())
1074        self.assertFalse(P('c:').is_absolute())
1075        self.assertFalse(P('c:a').is_absolute())
1076        self.assertFalse(P('c:a/b/').is_absolute())
1077        self.assertTrue(P('c:/').is_absolute())
1078        self.assertTrue(P('c:/a').is_absolute())
1079        self.assertTrue(P('c:/a/b/').is_absolute())
1080        # UNC paths are absolute by definition.
1081        self.assertTrue(P('//a/b').is_absolute())
1082        self.assertTrue(P('//a/b/').is_absolute())
1083        self.assertTrue(P('//a/b/c').is_absolute())
1084        self.assertTrue(P('//a/b/c/d').is_absolute())
1085
1086    def test_join(self):
1087        P = self.cls
1088        p = P('C:/a/b')
1089        pp = p.joinpath('x/y')
1090        self.assertEqual(pp, P('C:/a/b/x/y'))
1091        pp = p.joinpath('/x/y')
1092        self.assertEqual(pp, P('C:/x/y'))
1093        # Joining with a different drive => the first path is ignored, even
1094        # if the second path is relative.
1095        pp = p.joinpath('D:x/y')
1096        self.assertEqual(pp, P('D:x/y'))
1097        pp = p.joinpath('D:/x/y')
1098        self.assertEqual(pp, P('D:/x/y'))
1099        pp = p.joinpath('//host/share/x/y')
1100        self.assertEqual(pp, P('//host/share/x/y'))
1101        # Joining with the same drive => the first path is appended to if
1102        # the second path is relative.
1103        pp = p.joinpath('c:x/y')
1104        self.assertEqual(pp, P('C:/a/b/x/y'))
1105        pp = p.joinpath('c:/x/y')
1106        self.assertEqual(pp, P('C:/x/y'))
1107
1108    def test_div(self):
1109        # Basically the same as joinpath().
1110        P = self.cls
1111        p = P('C:/a/b')
1112        self.assertEqual(p / 'x/y', P('C:/a/b/x/y'))
1113        self.assertEqual(p / 'x' / 'y', P('C:/a/b/x/y'))
1114        self.assertEqual(p / '/x/y', P('C:/x/y'))
1115        self.assertEqual(p / '/x' / 'y', P('C:/x/y'))
1116        # Joining with a different drive => the first path is ignored, even
1117        # if the second path is relative.
1118        self.assertEqual(p / 'D:x/y', P('D:x/y'))
1119        self.assertEqual(p / 'D:' / 'x/y', P('D:x/y'))
1120        self.assertEqual(p / 'D:/x/y', P('D:/x/y'))
1121        self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y'))
1122        self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y'))
1123        # Joining with the same drive => the first path is appended to if
1124        # the second path is relative.
1125        self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y'))
1126        self.assertEqual(p / 'c:/x/y', P('C:/x/y'))
1127
1128    def test_is_reserved(self):
1129        P = self.cls
1130        self.assertIs(False, P('').is_reserved())
1131        self.assertIs(False, P('/').is_reserved())
1132        self.assertIs(False, P('/foo/bar').is_reserved())
1133        self.assertIs(True, P('con').is_reserved())
1134        self.assertIs(True, P('NUL').is_reserved())
1135        self.assertIs(True, P('NUL.txt').is_reserved())
1136        self.assertIs(True, P('com1').is_reserved())
1137        self.assertIs(True, P('com9.bar').is_reserved())
1138        self.assertIs(False, P('bar.com9').is_reserved())
1139        self.assertIs(True, P('lpt1').is_reserved())
1140        self.assertIs(True, P('lpt9.bar').is_reserved())
1141        self.assertIs(False, P('bar.lpt9').is_reserved())
1142        # Only the last component matters.
1143        self.assertIs(False, P('c:/NUL/con/baz').is_reserved())
1144        # UNC paths are never reserved.
1145        self.assertIs(False, P('//my/share/nul/con/aux').is_reserved())
1146
1147class PurePathTest(_BasePurePathTest, unittest.TestCase):
1148    cls = pathlib.PurePath
1149
1150    def test_concrete_class(self):
1151        p = self.cls('a')
1152        self.assertIs(type(p),
1153            pathlib.PureWindowsPath if os.name == 'nt' else pathlib.PurePosixPath)
1154
1155    def test_different_flavours_unequal(self):
1156        p = pathlib.PurePosixPath('a')
1157        q = pathlib.PureWindowsPath('a')
1158        self.assertNotEqual(p, q)
1159
1160    def test_different_flavours_unordered(self):
1161        p = pathlib.PurePosixPath('a')
1162        q = pathlib.PureWindowsPath('a')
1163        with self.assertRaises(TypeError):
1164            p < q
1165        with self.assertRaises(TypeError):
1166            p <= q
1167        with self.assertRaises(TypeError):
1168            p > q
1169        with self.assertRaises(TypeError):
1170            p >= q
1171
1172
1173#
1174# Tests for the concrete classes.
1175#
1176
1177# Make sure any symbolic links in the base test path are resolved.
1178BASE = os.path.realpath(TESTFN)
1179join = lambda *x: os.path.join(BASE, *x)
1180rel_join = lambda *x: os.path.join(TESTFN, *x)
1181
1182only_nt = unittest.skipIf(os.name != 'nt',
1183                          'test requires a Windows-compatible system')
1184only_posix = unittest.skipIf(os.name == 'nt',
1185                             'test requires a POSIX-compatible system')
1186
1187@only_posix
1188class PosixPathAsPureTest(PurePosixPathTest):
1189    cls = pathlib.PosixPath
1190
1191@only_nt
1192class WindowsPathAsPureTest(PureWindowsPathTest):
1193    cls = pathlib.WindowsPath
1194
1195    def test_owner(self):
1196        P = self.cls
1197        with self.assertRaises(NotImplementedError):
1198            P('c:/').owner()
1199
1200    def test_group(self):
1201        P = self.cls
1202        with self.assertRaises(NotImplementedError):
1203            P('c:/').group()
1204
1205
1206class _BasePathTest(object):
1207    """Tests for the FS-accessing functionalities of the Path classes."""
1208
1209    # (BASE)
1210    #  |
1211    #  |-- brokenLink -> non-existing
1212    #  |-- dirA
1213    #  |   `-- linkC -> ../dirB
1214    #  |-- dirB
1215    #  |   |-- fileB
1216    #  |   `-- linkD -> ../dirB
1217    #  |-- dirC
1218    #  |   |-- dirD
1219    #  |   |   `-- fileD
1220    #  |   `-- fileC
1221    #  |-- dirE  # No permissions
1222    #  |-- fileA
1223    #  |-- linkA -> fileA
1224    #  |-- linkB -> dirB
1225    #  `-- brokenLinkLoop -> brokenLinkLoop
1226    #
1227
1228    def setUp(self):
1229        def cleanup():
1230            os.chmod(join('dirE'), 0o777)
1231            support.rmtree(BASE)
1232        self.addCleanup(cleanup)
1233        os.mkdir(BASE)
1234        os.mkdir(join('dirA'))
1235        os.mkdir(join('dirB'))
1236        os.mkdir(join('dirC'))
1237        os.mkdir(join('dirC', 'dirD'))
1238        os.mkdir(join('dirE'))
1239        with open(join('fileA'), 'wb') as f:
1240            f.write(b"this is file A\n")
1241        with open(join('dirB', 'fileB'), 'wb') as f:
1242            f.write(b"this is file B\n")
1243        with open(join('dirC', 'fileC'), 'wb') as f:
1244            f.write(b"this is file C\n")
1245        with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
1246            f.write(b"this is file D\n")
1247        os.chmod(join('dirE'), 0)
1248        if support.can_symlink():
1249            # Relative symlinks.
1250            os.symlink('fileA', join('linkA'))
1251            os.symlink('non-existing', join('brokenLink'))
1252            self.dirlink('dirB', join('linkB'))
1253            self.dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC'))
1254            # This one goes upwards, creating a loop.
1255            self.dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD'))
1256            # Broken symlink (pointing to itself).
1257            os.symlink('brokenLinkLoop',  join('brokenLinkLoop'))
1258
1259    if os.name == 'nt':
1260        # Workaround for http://bugs.python.org/issue13772.
1261        def dirlink(self, src, dest):
1262            os.symlink(src, dest, target_is_directory=True)
1263    else:
1264        def dirlink(self, src, dest):
1265            os.symlink(src, dest)
1266
1267    def assertSame(self, path_a, path_b):
1268        self.assertTrue(os.path.samefile(str(path_a), str(path_b)),
1269                        "%r and %r don't point to the same file" %
1270                        (path_a, path_b))
1271
1272    def assertFileNotFound(self, func, *args, **kwargs):
1273        with self.assertRaises(FileNotFoundError) as cm:
1274            func(*args, **kwargs)
1275        self.assertEqual(cm.exception.errno, errno.ENOENT)
1276
1277    def assertEqualNormCase(self, path_a, path_b):
1278        self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b))
1279
1280    def _test_cwd(self, p):
1281        q = self.cls(os.getcwd())
1282        self.assertEqual(p, q)
1283        self.assertEqualNormCase(str(p), str(q))
1284        self.assertIs(type(p), type(q))
1285        self.assertTrue(p.is_absolute())
1286
1287    def test_cwd(self):
1288        p = self.cls.cwd()
1289        self._test_cwd(p)
1290
1291    def _test_home(self, p):
1292        q = self.cls(os.path.expanduser('~'))
1293        self.assertEqual(p, q)
1294        self.assertEqualNormCase(str(p), str(q))
1295        self.assertIs(type(p), type(q))
1296        self.assertTrue(p.is_absolute())
1297
1298    def test_home(self):
1299        with support.EnvironmentVarGuard() as env:
1300            self._test_home(self.cls.home())
1301
1302            env.clear()
1303            env['USERPROFILE'] = os.path.join(BASE, 'userprofile')
1304            self._test_home(self.cls.home())
1305
1306            # bpo-38883: ignore `HOME` when set on windows
1307            env['HOME'] = os.path.join(BASE, 'home')
1308            self._test_home(self.cls.home())
1309
1310    def test_samefile(self):
1311        fileA_path = os.path.join(BASE, 'fileA')
1312        fileB_path = os.path.join(BASE, 'dirB', 'fileB')
1313        p = self.cls(fileA_path)
1314        pp = self.cls(fileA_path)
1315        q = self.cls(fileB_path)
1316        self.assertTrue(p.samefile(fileA_path))
1317        self.assertTrue(p.samefile(pp))
1318        self.assertFalse(p.samefile(fileB_path))
1319        self.assertFalse(p.samefile(q))
1320        # Test the non-existent file case
1321        non_existent = os.path.join(BASE, 'foo')
1322        r = self.cls(non_existent)
1323        self.assertRaises(FileNotFoundError, p.samefile, r)
1324        self.assertRaises(FileNotFoundError, p.samefile, non_existent)
1325        self.assertRaises(FileNotFoundError, r.samefile, p)
1326        self.assertRaises(FileNotFoundError, r.samefile, non_existent)
1327        self.assertRaises(FileNotFoundError, r.samefile, r)
1328        self.assertRaises(FileNotFoundError, r.samefile, non_existent)
1329
1330    def test_empty_path(self):
1331        # The empty path points to '.'
1332        p = self.cls('')
1333        self.assertEqual(p.stat(), os.stat('.'))
1334
1335    def test_expanduser_common(self):
1336        P = self.cls
1337        p = P('~')
1338        self.assertEqual(p.expanduser(), P(os.path.expanduser('~')))
1339        p = P('foo')
1340        self.assertEqual(p.expanduser(), p)
1341        p = P('/~')
1342        self.assertEqual(p.expanduser(), p)
1343        p = P('../~')
1344        self.assertEqual(p.expanduser(), p)
1345        p = P(P('').absolute().anchor) / '~'
1346        self.assertEqual(p.expanduser(), p)
1347
1348    def test_exists(self):
1349        P = self.cls
1350        p = P(BASE)
1351        self.assertIs(True, p.exists())
1352        self.assertIs(True, (p / 'dirA').exists())
1353        self.assertIs(True, (p / 'fileA').exists())
1354        self.assertIs(False, (p / 'fileA' / 'bah').exists())
1355        if support.can_symlink():
1356            self.assertIs(True, (p / 'linkA').exists())
1357            self.assertIs(True, (p / 'linkB').exists())
1358            self.assertIs(True, (p / 'linkB' / 'fileB').exists())
1359            self.assertIs(False, (p / 'linkA' / 'bah').exists())
1360        self.assertIs(False, (p / 'foo').exists())
1361        self.assertIs(False, P('/xyzzy').exists())
1362        self.assertIs(False, P(BASE + '\udfff').exists())
1363        self.assertIs(False, P(BASE + '\x00').exists())
1364
1365    def test_open_common(self):
1366        p = self.cls(BASE)
1367        with (p / 'fileA').open('r') as f:
1368            self.assertIsInstance(f, io.TextIOBase)
1369            self.assertEqual(f.read(), "this is file A\n")
1370        with (p / 'fileA').open('rb') as f:
1371            self.assertIsInstance(f, io.BufferedIOBase)
1372            self.assertEqual(f.read().strip(), b"this is file A")
1373        with (p / 'fileA').open('rb', buffering=0) as f:
1374            self.assertIsInstance(f, io.RawIOBase)
1375            self.assertEqual(f.read().strip(), b"this is file A")
1376
1377    def test_read_write_bytes(self):
1378        p = self.cls(BASE)
1379        (p / 'fileA').write_bytes(b'abcdefg')
1380        self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
1381        # Check that trying to write str does not truncate the file.
1382        self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr')
1383        self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
1384
1385    def test_read_write_text(self):
1386        p = self.cls(BASE)
1387        (p / 'fileA').write_text('äbcdefg', encoding='latin-1')
1388        self.assertEqual((p / 'fileA').read_text(
1389            encoding='utf-8', errors='ignore'), 'bcdefg')
1390        # Check that trying to write bytes does not truncate the file.
1391        self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes')
1392        self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg')
1393
1394    def test_iterdir(self):
1395        P = self.cls
1396        p = P(BASE)
1397        it = p.iterdir()
1398        paths = set(it)
1399        expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
1400        if support.can_symlink():
1401            expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop']
1402        self.assertEqual(paths, { P(BASE, q) for q in expected })
1403
1404    @support.skip_unless_symlink
1405    def test_iterdir_symlink(self):
1406        # __iter__ on a symlink to a directory.
1407        P = self.cls
1408        p = P(BASE, 'linkB')
1409        paths = set(p.iterdir())
1410        expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] }
1411        self.assertEqual(paths, expected)
1412
1413    def test_iterdir_nodir(self):
1414        # __iter__ on something that is not a directory.
1415        p = self.cls(BASE, 'fileA')
1416        with self.assertRaises(OSError) as cm:
1417            next(p.iterdir())
1418        # ENOENT or EINVAL under Windows, ENOTDIR otherwise
1419        # (see issue #12802).
1420        self.assertIn(cm.exception.errno, (errno.ENOTDIR,
1421                                           errno.ENOENT, errno.EINVAL))
1422
1423    def test_glob_common(self):
1424        def _check(glob, expected):
1425            self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1426        P = self.cls
1427        p = P(BASE)
1428        it = p.glob("fileA")
1429        self.assertIsInstance(it, collections.abc.Iterator)
1430        _check(it, ["fileA"])
1431        _check(p.glob("fileB"), [])
1432        _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
1433        if not support.can_symlink():
1434            _check(p.glob("*A"), ['dirA', 'fileA'])
1435        else:
1436            _check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
1437        if not support.can_symlink():
1438            _check(p.glob("*B/*"), ['dirB/fileB'])
1439        else:
1440            _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
1441                                    'linkB/fileB', 'linkB/linkD'])
1442        if not support.can_symlink():
1443            _check(p.glob("*/fileB"), ['dirB/fileB'])
1444        else:
1445            _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1446
1447    def test_rglob_common(self):
1448        def _check(glob, expected):
1449            self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1450        P = self.cls
1451        p = P(BASE)
1452        it = p.rglob("fileA")
1453        self.assertIsInstance(it, collections.abc.Iterator)
1454        _check(it, ["fileA"])
1455        _check(p.rglob("fileB"), ["dirB/fileB"])
1456        _check(p.rglob("*/fileA"), [])
1457        if not support.can_symlink():
1458            _check(p.rglob("*/fileB"), ["dirB/fileB"])
1459        else:
1460            _check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
1461                                        "linkB/fileB", "dirA/linkC/fileB"])
1462        _check(p.rglob("file*"), ["fileA", "dirB/fileB",
1463                                  "dirC/fileC", "dirC/dirD/fileD"])
1464        p = P(BASE, "dirC")
1465        _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1466        _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1467
1468    @support.skip_unless_symlink
1469    def test_rglob_symlink_loop(self):
1470        # Don't get fooled by symlink loops (Issue #26012).
1471        P = self.cls
1472        p = P(BASE)
1473        given = set(p.rglob('*'))
1474        expect = {'brokenLink',
1475                  'dirA', 'dirA/linkC',
1476                  'dirB', 'dirB/fileB', 'dirB/linkD',
1477                  'dirC', 'dirC/dirD', 'dirC/dirD/fileD', 'dirC/fileC',
1478                  'dirE',
1479                  'fileA',
1480                  'linkA',
1481                  'linkB',
1482                  'brokenLinkLoop',
1483                  }
1484        self.assertEqual(given, {p / x for x in expect})
1485
1486    def test_glob_many_open_files(self):
1487        depth = 30
1488        P = self.cls
1489        base = P(BASE) / 'deep'
1490        p = P(base, *(['d']*depth))
1491        p.mkdir(parents=True)
1492        pattern = '/'.join(['*'] * depth)
1493        iters = [base.glob(pattern) for j in range(100)]
1494        for it in iters:
1495            self.assertEqual(next(it), p)
1496        iters = [base.rglob('d') for j in range(100)]
1497        p = base
1498        for i in range(depth):
1499            p = p / 'd'
1500            for it in iters:
1501                self.assertEqual(next(it), p)
1502
1503    def test_glob_dotdot(self):
1504        # ".." is not special in globs.
1505        P = self.cls
1506        p = P(BASE)
1507        self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
1508        self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
1509        self.assertEqual(set(p.glob("../xyzzy")), set())
1510
1511    @support.skip_unless_symlink
1512    def test_glob_permissions(self):
1513        # See bpo-38894
1514        P = self.cls
1515        base = P(BASE) / 'permissions'
1516        base.mkdir()
1517
1518        file1 = base / "file1"
1519        file1.touch()
1520        file2 = base / "file2"
1521        file2.touch()
1522
1523        subdir = base / "subdir"
1524
1525        file3 = base / "file3"
1526        file3.symlink_to(subdir / "other")
1527
1528        # Patching is needed to avoid relying on the filesystem
1529        # to return the order of the files as the error will not
1530        # happen if the symlink is the last item.
1531
1532        with mock.patch("os.scandir") as scandir:
1533            scandir.return_value = sorted(os.scandir(base))
1534            self.assertEqual(len(set(base.glob("*"))), 3)
1535
1536        subdir.mkdir()
1537
1538        with mock.patch("os.scandir") as scandir:
1539            scandir.return_value = sorted(os.scandir(base))
1540            self.assertEqual(len(set(base.glob("*"))), 4)
1541
1542        subdir.chmod(000)
1543
1544        with mock.patch("os.scandir") as scandir:
1545            scandir.return_value = sorted(os.scandir(base))
1546            self.assertEqual(len(set(base.glob("*"))), 4)
1547
1548    def _check_resolve(self, p, expected, strict=True):
1549        q = p.resolve(strict)
1550        self.assertEqual(q, expected)
1551
1552    # This can be used to check both relative and absolute resolutions.
1553    _check_resolve_relative = _check_resolve_absolute = _check_resolve
1554
1555    @support.skip_unless_symlink
1556    def test_resolve_common(self):
1557        P = self.cls
1558        p = P(BASE, 'foo')
1559        with self.assertRaises(OSError) as cm:
1560            p.resolve(strict=True)
1561        self.assertEqual(cm.exception.errno, errno.ENOENT)
1562        # Non-strict
1563        self.assertEqualNormCase(str(p.resolve(strict=False)),
1564                                 os.path.join(BASE, 'foo'))
1565        p = P(BASE, 'foo', 'in', 'spam')
1566        self.assertEqualNormCase(str(p.resolve(strict=False)),
1567                                 os.path.join(BASE, 'foo', 'in', 'spam'))
1568        p = P(BASE, '..', 'foo', 'in', 'spam')
1569        self.assertEqualNormCase(str(p.resolve(strict=False)),
1570                                 os.path.abspath(os.path.join('foo', 'in', 'spam')))
1571        # These are all relative symlinks.
1572        p = P(BASE, 'dirB', 'fileB')
1573        self._check_resolve_relative(p, p)
1574        p = P(BASE, 'linkA')
1575        self._check_resolve_relative(p, P(BASE, 'fileA'))
1576        p = P(BASE, 'dirA', 'linkC', 'fileB')
1577        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1578        p = P(BASE, 'dirB', 'linkD', 'fileB')
1579        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1580        # Non-strict
1581        p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
1582        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo', 'in',
1583                                          'spam'), False)
1584        p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
1585        if os.name == 'nt':
1586            # In Windows, if linkY points to dirB, 'dirA\linkY\..'
1587            # resolves to 'dirA' without resolving linkY first.
1588            self._check_resolve_relative(p, P(BASE, 'dirA', 'foo', 'in',
1589                                              'spam'), False)
1590        else:
1591            # In Posix, if linkY points to dirB, 'dirA/linkY/..'
1592            # resolves to 'dirB/..' first before resolving to parent of dirB.
1593            self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
1594        # Now create absolute symlinks.
1595        d = support._longpath(tempfile.mkdtemp(suffix='-dirD', dir=os.getcwd()))
1596        self.addCleanup(support.rmtree, d)
1597        os.symlink(os.path.join(d), join('dirA', 'linkX'))
1598        os.symlink(join('dirB'), os.path.join(d, 'linkY'))
1599        p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB')
1600        self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
1601        # Non-strict
1602        p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
1603        self._check_resolve_relative(p, P(BASE, 'dirB', 'foo', 'in', 'spam'),
1604                                     False)
1605        p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
1606        if os.name == 'nt':
1607            # In Windows, if linkY points to dirB, 'dirA\linkY\..'
1608            # resolves to 'dirA' without resolving linkY first.
1609            self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
1610        else:
1611            # In Posix, if linkY points to dirB, 'dirA/linkY/..'
1612            # resolves to 'dirB/..' first before resolving to parent of dirB.
1613            self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
1614
1615    @support.skip_unless_symlink
1616    def test_resolve_dot(self):
1617        # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks
1618        p = self.cls(BASE)
1619        self.dirlink('.', join('0'))
1620        self.dirlink(os.path.join('0', '0'), join('1'))
1621        self.dirlink(os.path.join('1', '1'), join('2'))
1622        q = p / '2'
1623        self.assertEqual(q.resolve(strict=True), p)
1624        r = q / '3' / '4'
1625        self.assertRaises(FileNotFoundError, r.resolve, strict=True)
1626        # Non-strict
1627        self.assertEqual(r.resolve(strict=False), p / '3' / '4')
1628
1629    def test_with(self):
1630        p = self.cls(BASE)
1631        it = p.iterdir()
1632        it2 = p.iterdir()
1633        next(it2)
1634        with p:
1635            pass
1636        # I/O operation on closed path.
1637        self.assertRaises(ValueError, next, it)
1638        self.assertRaises(ValueError, next, it2)
1639        self.assertRaises(ValueError, p.open)
1640        self.assertRaises(ValueError, p.resolve)
1641        self.assertRaises(ValueError, p.absolute)
1642        self.assertRaises(ValueError, p.__enter__)
1643
1644    def test_chmod(self):
1645        p = self.cls(BASE) / 'fileA'
1646        mode = p.stat().st_mode
1647        # Clear writable bit.
1648        new_mode = mode & ~0o222
1649        p.chmod(new_mode)
1650        self.assertEqual(p.stat().st_mode, new_mode)
1651        # Set writable bit.
1652        new_mode = mode | 0o222
1653        p.chmod(new_mode)
1654        self.assertEqual(p.stat().st_mode, new_mode)
1655
1656    # XXX also need a test for lchmod.
1657
1658    def test_stat(self):
1659        p = self.cls(BASE) / 'fileA'
1660        st = p.stat()
1661        self.assertEqual(p.stat(), st)
1662        # Change file mode by flipping write bit.
1663        p.chmod(st.st_mode ^ 0o222)
1664        self.addCleanup(p.chmod, st.st_mode)
1665        self.assertNotEqual(p.stat(), st)
1666
1667    @support.skip_unless_symlink
1668    def test_lstat(self):
1669        p = self.cls(BASE)/ 'linkA'
1670        st = p.stat()
1671        self.assertNotEqual(st, p.lstat())
1672
1673    def test_lstat_nosymlink(self):
1674        p = self.cls(BASE) / 'fileA'
1675        st = p.stat()
1676        self.assertEqual(st, p.lstat())
1677
1678    @unittest.skipUnless(pwd, "the pwd module is needed for this test")
1679    def test_owner(self):
1680        p = self.cls(BASE) / 'fileA'
1681        uid = p.stat().st_uid
1682        try:
1683            name = pwd.getpwuid(uid).pw_name
1684        except KeyError:
1685            self.skipTest(
1686                "user %d doesn't have an entry in the system database" % uid)
1687        self.assertEqual(name, p.owner())
1688
1689    @unittest.skipUnless(grp, "the grp module is needed for this test")
1690    def test_group(self):
1691        p = self.cls(BASE) / 'fileA'
1692        gid = p.stat().st_gid
1693        try:
1694            name = grp.getgrgid(gid).gr_name
1695        except KeyError:
1696            self.skipTest(
1697                "group %d doesn't have an entry in the system database" % gid)
1698        self.assertEqual(name, p.group())
1699
1700    def test_unlink(self):
1701        p = self.cls(BASE) / 'fileA'
1702        p.unlink()
1703        self.assertFileNotFound(p.stat)
1704        self.assertFileNotFound(p.unlink)
1705
1706    def test_unlink_missing_ok(self):
1707        p = self.cls(BASE) / 'fileAAA'
1708        self.assertFileNotFound(p.unlink)
1709        p.unlink(missing_ok=True)
1710
1711    def test_rmdir(self):
1712        p = self.cls(BASE) / 'dirA'
1713        for q in p.iterdir():
1714            q.unlink()
1715        p.rmdir()
1716        self.assertFileNotFound(p.stat)
1717        self.assertFileNotFound(p.unlink)
1718
1719    @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present")
1720    def test_link_to(self):
1721        P = self.cls(BASE)
1722        p = P / 'fileA'
1723        size = p.stat().st_size
1724        # linking to another path.
1725        q = P / 'dirA' / 'fileAA'
1726        try:
1727            p.link_to(q)
1728        except PermissionError as e:
1729            self.skipTest('os.link(): %s' % e)
1730        self.assertEqual(q.stat().st_size, size)
1731        self.assertEqual(os.path.samefile(p, q), True)
1732        self.assertTrue(p.stat)
1733        # Linking to a str of a relative path.
1734        r = rel_join('fileAAA')
1735        q.link_to(r)
1736        self.assertEqual(os.stat(r).st_size, size)
1737        self.assertTrue(q.stat)
1738
1739    @unittest.skipIf(hasattr(os, "link"), "os.link() is present")
1740    def test_link_to_not_implemented(self):
1741        P = self.cls(BASE)
1742        p = P / 'fileA'
1743        # linking to another path.
1744        q = P / 'dirA' / 'fileAA'
1745        with self.assertRaises(NotImplementedError):
1746            p.link_to(q)
1747
1748    def test_rename(self):
1749        P = self.cls(BASE)
1750        p = P / 'fileA'
1751        size = p.stat().st_size
1752        # Renaming to another path.
1753        q = P / 'dirA' / 'fileAA'
1754        renamed_p = p.rename(q)
1755        self.assertEqual(renamed_p, q)
1756        self.assertEqual(q.stat().st_size, size)
1757        self.assertFileNotFound(p.stat)
1758        # Renaming to a str of a relative path.
1759        r = rel_join('fileAAA')
1760        renamed_q = q.rename(r)
1761        self.assertEqual(renamed_q, self.cls(r))
1762        self.assertEqual(os.stat(r).st_size, size)
1763        self.assertFileNotFound(q.stat)
1764
1765    def test_replace(self):
1766        P = self.cls(BASE)
1767        p = P / 'fileA'
1768        size = p.stat().st_size
1769        # Replacing a non-existing path.
1770        q = P / 'dirA' / 'fileAA'
1771        replaced_p = p.replace(q)
1772        self.assertEqual(replaced_p, q)
1773        self.assertEqual(q.stat().st_size, size)
1774        self.assertFileNotFound(p.stat)
1775        # Replacing another (existing) path.
1776        r = rel_join('dirB', 'fileB')
1777        replaced_q = q.replace(r)
1778        self.assertEqual(replaced_q, self.cls(r))
1779        self.assertEqual(os.stat(r).st_size, size)
1780        self.assertFileNotFound(q.stat)
1781
1782    def test_touch_common(self):
1783        P = self.cls(BASE)
1784        p = P / 'newfileA'
1785        self.assertFalse(p.exists())
1786        p.touch()
1787        self.assertTrue(p.exists())
1788        st = p.stat()
1789        old_mtime = st.st_mtime
1790        old_mtime_ns = st.st_mtime_ns
1791        # Rewind the mtime sufficiently far in the past to work around
1792        # filesystem-specific timestamp granularity.
1793        os.utime(str(p), (old_mtime - 10, old_mtime - 10))
1794        # The file mtime should be refreshed by calling touch() again.
1795        p.touch()
1796        st = p.stat()
1797        self.assertGreaterEqual(st.st_mtime_ns, old_mtime_ns)
1798        self.assertGreaterEqual(st.st_mtime, old_mtime)
1799        # Now with exist_ok=False.
1800        p = P / 'newfileB'
1801        self.assertFalse(p.exists())
1802        p.touch(mode=0o700, exist_ok=False)
1803        self.assertTrue(p.exists())
1804        self.assertRaises(OSError, p.touch, exist_ok=False)
1805
1806    def test_touch_nochange(self):
1807        P = self.cls(BASE)
1808        p = P / 'fileA'
1809        p.touch()
1810        with p.open('rb') as f:
1811            self.assertEqual(f.read().strip(), b"this is file A")
1812
1813    def test_mkdir(self):
1814        P = self.cls(BASE)
1815        p = P / 'newdirA'
1816        self.assertFalse(p.exists())
1817        p.mkdir()
1818        self.assertTrue(p.exists())
1819        self.assertTrue(p.is_dir())
1820        with self.assertRaises(OSError) as cm:
1821            p.mkdir()
1822        self.assertEqual(cm.exception.errno, errno.EEXIST)
1823
1824    def test_mkdir_parents(self):
1825        # Creating a chain of directories.
1826        p = self.cls(BASE, 'newdirB', 'newdirC')
1827        self.assertFalse(p.exists())
1828        with self.assertRaises(OSError) as cm:
1829            p.mkdir()
1830        self.assertEqual(cm.exception.errno, errno.ENOENT)
1831        p.mkdir(parents=True)
1832        self.assertTrue(p.exists())
1833        self.assertTrue(p.is_dir())
1834        with self.assertRaises(OSError) as cm:
1835            p.mkdir(parents=True)
1836        self.assertEqual(cm.exception.errno, errno.EEXIST)
1837        # Test `mode` arg.
1838        mode = stat.S_IMODE(p.stat().st_mode)  # Default mode.
1839        p = self.cls(BASE, 'newdirD', 'newdirE')
1840        p.mkdir(0o555, parents=True)
1841        self.assertTrue(p.exists())
1842        self.assertTrue(p.is_dir())
1843        if os.name != 'nt':
1844            # The directory's permissions follow the mode argument.
1845            self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode)
1846        # The parent's permissions follow the default process settings.
1847        self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
1848
1849    def test_mkdir_exist_ok(self):
1850        p = self.cls(BASE, 'dirB')
1851        st_ctime_first = p.stat().st_ctime
1852        self.assertTrue(p.exists())
1853        self.assertTrue(p.is_dir())
1854        with self.assertRaises(FileExistsError) as cm:
1855            p.mkdir()
1856        self.assertEqual(cm.exception.errno, errno.EEXIST)
1857        p.mkdir(exist_ok=True)
1858        self.assertTrue(p.exists())
1859        self.assertEqual(p.stat().st_ctime, st_ctime_first)
1860
1861    def test_mkdir_exist_ok_with_parent(self):
1862        p = self.cls(BASE, 'dirC')
1863        self.assertTrue(p.exists())
1864        with self.assertRaises(FileExistsError) as cm:
1865            p.mkdir()
1866        self.assertEqual(cm.exception.errno, errno.EEXIST)
1867        p = p / 'newdirC'
1868        p.mkdir(parents=True)
1869        st_ctime_first = p.stat().st_ctime
1870        self.assertTrue(p.exists())
1871        with self.assertRaises(FileExistsError) as cm:
1872            p.mkdir(parents=True)
1873        self.assertEqual(cm.exception.errno, errno.EEXIST)
1874        p.mkdir(parents=True, exist_ok=True)
1875        self.assertTrue(p.exists())
1876        self.assertEqual(p.stat().st_ctime, st_ctime_first)
1877
1878    def test_mkdir_exist_ok_root(self):
1879        # Issue #25803: A drive root could raise PermissionError on Windows.
1880        self.cls('/').resolve().mkdir(exist_ok=True)
1881        self.cls('/').resolve().mkdir(parents=True, exist_ok=True)
1882
1883    @only_nt  # XXX: not sure how to test this on POSIX.
1884    def test_mkdir_with_unknown_drive(self):
1885        for d in 'ZYXWVUTSRQPONMLKJIHGFEDCBA':
1886            p = self.cls(d + ':\\')
1887            if not p.is_dir():
1888                break
1889        else:
1890            self.skipTest("cannot find a drive that doesn't exist")
1891        with self.assertRaises(OSError):
1892            (p / 'child' / 'path').mkdir(parents=True)
1893
1894    def test_mkdir_with_child_file(self):
1895        p = self.cls(BASE, 'dirB', 'fileB')
1896        self.assertTrue(p.exists())
1897        # An exception is raised when the last path component is an existing
1898        # regular file, regardless of whether exist_ok is true or not.
1899        with self.assertRaises(FileExistsError) as cm:
1900            p.mkdir(parents=True)
1901        self.assertEqual(cm.exception.errno, errno.EEXIST)
1902        with self.assertRaises(FileExistsError) as cm:
1903            p.mkdir(parents=True, exist_ok=True)
1904        self.assertEqual(cm.exception.errno, errno.EEXIST)
1905
1906    def test_mkdir_no_parents_file(self):
1907        p = self.cls(BASE, 'fileA')
1908        self.assertTrue(p.exists())
1909        # An exception is raised when the last path component is an existing
1910        # regular file, regardless of whether exist_ok is true or not.
1911        with self.assertRaises(FileExistsError) as cm:
1912            p.mkdir()
1913        self.assertEqual(cm.exception.errno, errno.EEXIST)
1914        with self.assertRaises(FileExistsError) as cm:
1915            p.mkdir(exist_ok=True)
1916        self.assertEqual(cm.exception.errno, errno.EEXIST)
1917
1918    def test_mkdir_concurrent_parent_creation(self):
1919        for pattern_num in range(32):
1920            p = self.cls(BASE, 'dirCPC%d' % pattern_num)
1921            self.assertFalse(p.exists())
1922
1923            def my_mkdir(path, mode=0o777):
1924                path = str(path)
1925                # Emulate another process that would create the directory
1926                # just before we try to create it ourselves.  We do it
1927                # in all possible pattern combinations, assuming that this
1928                # function is called at most 5 times (dirCPC/dir1/dir2,
1929                # dirCPC/dir1, dirCPC, dirCPC/dir1, dirCPC/dir1/dir2).
1930                if pattern.pop():
1931                    os.mkdir(path, mode)  # From another process.
1932                    concurrently_created.add(path)
1933                os.mkdir(path, mode)  # Our real call.
1934
1935            pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
1936            concurrently_created = set()
1937            p12 = p / 'dir1' / 'dir2'
1938            try:
1939                with mock.patch("pathlib._normal_accessor.mkdir", my_mkdir):
1940                    p12.mkdir(parents=True, exist_ok=False)
1941            except FileExistsError:
1942                self.assertIn(str(p12), concurrently_created)
1943            else:
1944                self.assertNotIn(str(p12), concurrently_created)
1945            self.assertTrue(p.exists())
1946
1947    @support.skip_unless_symlink
1948    def test_symlink_to(self):
1949        P = self.cls(BASE)
1950        target = P / 'fileA'
1951        # Symlinking a path target.
1952        link = P / 'dirA' / 'linkAA'
1953        link.symlink_to(target)
1954        self.assertEqual(link.stat(), target.stat())
1955        self.assertNotEqual(link.lstat(), target.stat())
1956        # Symlinking a str target.
1957        link = P / 'dirA' / 'linkAAA'
1958        link.symlink_to(str(target))
1959        self.assertEqual(link.stat(), target.stat())
1960        self.assertNotEqual(link.lstat(), target.stat())
1961        self.assertFalse(link.is_dir())
1962        # Symlinking to a directory.
1963        target = P / 'dirB'
1964        link = P / 'dirA' / 'linkAAAA'
1965        link.symlink_to(target, target_is_directory=True)
1966        self.assertEqual(link.stat(), target.stat())
1967        self.assertNotEqual(link.lstat(), target.stat())
1968        self.assertTrue(link.is_dir())
1969        self.assertTrue(list(link.iterdir()))
1970
1971    def test_is_dir(self):
1972        P = self.cls(BASE)
1973        self.assertTrue((P / 'dirA').is_dir())
1974        self.assertFalse((P / 'fileA').is_dir())
1975        self.assertFalse((P / 'non-existing').is_dir())
1976        self.assertFalse((P / 'fileA' / 'bah').is_dir())
1977        if support.can_symlink():
1978            self.assertFalse((P / 'linkA').is_dir())
1979            self.assertTrue((P / 'linkB').is_dir())
1980            self.assertFalse((P/ 'brokenLink').is_dir(), False)
1981        self.assertIs((P / 'dirA\udfff').is_dir(), False)
1982        self.assertIs((P / 'dirA\x00').is_dir(), False)
1983
1984    def test_is_file(self):
1985        P = self.cls(BASE)
1986        self.assertTrue((P / 'fileA').is_file())
1987        self.assertFalse((P / 'dirA').is_file())
1988        self.assertFalse((P / 'non-existing').is_file())
1989        self.assertFalse((P / 'fileA' / 'bah').is_file())
1990        if support.can_symlink():
1991            self.assertTrue((P / 'linkA').is_file())
1992            self.assertFalse((P / 'linkB').is_file())
1993            self.assertFalse((P/ 'brokenLink').is_file())
1994        self.assertIs((P / 'fileA\udfff').is_file(), False)
1995        self.assertIs((P / 'fileA\x00').is_file(), False)
1996
1997    @only_posix
1998    def test_is_mount(self):
1999        P = self.cls(BASE)
2000        R = self.cls('/')  # TODO: Work out Windows.
2001        self.assertFalse((P / 'fileA').is_mount())
2002        self.assertFalse((P / 'dirA').is_mount())
2003        self.assertFalse((P / 'non-existing').is_mount())
2004        self.assertFalse((P / 'fileA' / 'bah').is_mount())
2005        self.assertTrue(R.is_mount())
2006        if support.can_symlink():
2007            self.assertFalse((P / 'linkA').is_mount())
2008        self.assertIs(self.cls('/\udfff').is_mount(), False)
2009        self.assertIs(self.cls('/\x00').is_mount(), False)
2010
2011    def test_is_symlink(self):
2012        P = self.cls(BASE)
2013        self.assertFalse((P / 'fileA').is_symlink())
2014        self.assertFalse((P / 'dirA').is_symlink())
2015        self.assertFalse((P / 'non-existing').is_symlink())
2016        self.assertFalse((P / 'fileA' / 'bah').is_symlink())
2017        if support.can_symlink():
2018            self.assertTrue((P / 'linkA').is_symlink())
2019            self.assertTrue((P / 'linkB').is_symlink())
2020            self.assertTrue((P/ 'brokenLink').is_symlink())
2021        self.assertIs((P / 'fileA\udfff').is_file(), False)
2022        self.assertIs((P / 'fileA\x00').is_file(), False)
2023        if support.can_symlink():
2024            self.assertIs((P / 'linkA\udfff').is_file(), False)
2025            self.assertIs((P / 'linkA\x00').is_file(), False)
2026
2027    def test_is_fifo_false(self):
2028        P = self.cls(BASE)
2029        self.assertFalse((P / 'fileA').is_fifo())
2030        self.assertFalse((P / 'dirA').is_fifo())
2031        self.assertFalse((P / 'non-existing').is_fifo())
2032        self.assertFalse((P / 'fileA' / 'bah').is_fifo())
2033        self.assertIs((P / 'fileA\udfff').is_fifo(), False)
2034        self.assertIs((P / 'fileA\x00').is_fifo(), False)
2035
2036    @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required")
2037    def test_is_fifo_true(self):
2038        P = self.cls(BASE, 'myfifo')
2039        try:
2040            os.mkfifo(str(P))
2041        except PermissionError as e:
2042            self.skipTest('os.mkfifo(): %s' % e)
2043        self.assertTrue(P.is_fifo())
2044        self.assertFalse(P.is_socket())
2045        self.assertFalse(P.is_file())
2046        self.assertIs(self.cls(BASE, 'myfifo\udfff').is_fifo(), False)
2047        self.assertIs(self.cls(BASE, 'myfifo\x00').is_fifo(), False)
2048
2049    def test_is_socket_false(self):
2050        P = self.cls(BASE)
2051        self.assertFalse((P / 'fileA').is_socket())
2052        self.assertFalse((P / 'dirA').is_socket())
2053        self.assertFalse((P / 'non-existing').is_socket())
2054        self.assertFalse((P / 'fileA' / 'bah').is_socket())
2055        self.assertIs((P / 'fileA\udfff').is_socket(), False)
2056        self.assertIs((P / 'fileA\x00').is_socket(), False)
2057
2058    @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
2059    def test_is_socket_true(self):
2060        P = self.cls(BASE, 'mysock')
2061        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
2062        self.addCleanup(sock.close)
2063        try:
2064            sock.bind(str(P))
2065        except OSError as e:
2066            if (isinstance(e, PermissionError) or
2067                    "AF_UNIX path too long" in str(e)):
2068                self.skipTest("cannot bind Unix socket: " + str(e))
2069        self.assertTrue(P.is_socket())
2070        self.assertFalse(P.is_fifo())
2071        self.assertFalse(P.is_file())
2072        self.assertIs(self.cls(BASE, 'mysock\udfff').is_socket(), False)
2073        self.assertIs(self.cls(BASE, 'mysock\x00').is_socket(), False)
2074
2075    def test_is_block_device_false(self):
2076        P = self.cls(BASE)
2077        self.assertFalse((P / 'fileA').is_block_device())
2078        self.assertFalse((P / 'dirA').is_block_device())
2079        self.assertFalse((P / 'non-existing').is_block_device())
2080        self.assertFalse((P / 'fileA' / 'bah').is_block_device())
2081        self.assertIs((P / 'fileA\udfff').is_block_device(), False)
2082        self.assertIs((P / 'fileA\x00').is_block_device(), False)
2083
2084    def test_is_char_device_false(self):
2085        P = self.cls(BASE)
2086        self.assertFalse((P / 'fileA').is_char_device())
2087        self.assertFalse((P / 'dirA').is_char_device())
2088        self.assertFalse((P / 'non-existing').is_char_device())
2089        self.assertFalse((P / 'fileA' / 'bah').is_char_device())
2090        self.assertIs((P / 'fileA\udfff').is_char_device(), False)
2091        self.assertIs((P / 'fileA\x00').is_char_device(), False)
2092
2093    def test_is_char_device_true(self):
2094        # Under Unix, /dev/null should generally be a char device.
2095        P = self.cls('/dev/null')
2096        if not P.exists():
2097            self.skipTest("/dev/null required")
2098        self.assertTrue(P.is_char_device())
2099        self.assertFalse(P.is_block_device())
2100        self.assertFalse(P.is_file())
2101        self.assertIs(self.cls('/dev/null\udfff').is_char_device(), False)
2102        self.assertIs(self.cls('/dev/null\x00').is_char_device(), False)
2103
2104    def test_pickling_common(self):
2105        p = self.cls(BASE, 'fileA')
2106        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
2107            dumped = pickle.dumps(p, proto)
2108            pp = pickle.loads(dumped)
2109            self.assertEqual(pp.stat(), p.stat())
2110
2111    def test_parts_interning(self):
2112        P = self.cls
2113        p = P('/usr/bin/foo')
2114        q = P('/usr/local/bin')
2115        # 'usr'
2116        self.assertIs(p.parts[1], q.parts[1])
2117        # 'bin'
2118        self.assertIs(p.parts[2], q.parts[3])
2119
2120    def _check_complex_symlinks(self, link0_target):
2121        # Test solving a non-looping chain of symlinks (issue #19887).
2122        P = self.cls(BASE)
2123        self.dirlink(os.path.join('link0', 'link0'), join('link1'))
2124        self.dirlink(os.path.join('link1', 'link1'), join('link2'))
2125        self.dirlink(os.path.join('link2', 'link2'), join('link3'))
2126        self.dirlink(link0_target, join('link0'))
2127
2128        # Resolve absolute paths.
2129        p = (P / 'link0').resolve()
2130        self.assertEqual(p, P)
2131        self.assertEqualNormCase(str(p), BASE)
2132        p = (P / 'link1').resolve()
2133        self.assertEqual(p, P)
2134        self.assertEqualNormCase(str(p), BASE)
2135        p = (P / 'link2').resolve()
2136        self.assertEqual(p, P)
2137        self.assertEqualNormCase(str(p), BASE)
2138        p = (P / 'link3').resolve()
2139        self.assertEqual(p, P)
2140        self.assertEqualNormCase(str(p), BASE)
2141
2142        # Resolve relative paths.
2143        old_path = os.getcwd()
2144        os.chdir(BASE)
2145        try:
2146            p = self.cls('link0').resolve()
2147            self.assertEqual(p, P)
2148            self.assertEqualNormCase(str(p), BASE)
2149            p = self.cls('link1').resolve()
2150            self.assertEqual(p, P)
2151            self.assertEqualNormCase(str(p), BASE)
2152            p = self.cls('link2').resolve()
2153            self.assertEqual(p, P)
2154            self.assertEqualNormCase(str(p), BASE)
2155            p = self.cls('link3').resolve()
2156            self.assertEqual(p, P)
2157            self.assertEqualNormCase(str(p), BASE)
2158        finally:
2159            os.chdir(old_path)
2160
2161    @support.skip_unless_symlink
2162    def test_complex_symlinks_absolute(self):
2163        self._check_complex_symlinks(BASE)
2164
2165    @support.skip_unless_symlink
2166    def test_complex_symlinks_relative(self):
2167        self._check_complex_symlinks('.')
2168
2169    @support.skip_unless_symlink
2170    def test_complex_symlinks_relative_dot_dot(self):
2171        self._check_complex_symlinks(os.path.join('dirA', '..'))
2172
2173
2174class PathTest(_BasePathTest, unittest.TestCase):
2175    cls = pathlib.Path
2176
2177    def test_concrete_class(self):
2178        p = self.cls('a')
2179        self.assertIs(type(p),
2180            pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath)
2181
2182    def test_unsupported_flavour(self):
2183        if os.name == 'nt':
2184            self.assertRaises(NotImplementedError, pathlib.PosixPath)
2185        else:
2186            self.assertRaises(NotImplementedError, pathlib.WindowsPath)
2187
2188    def test_glob_empty_pattern(self):
2189        p = self.cls()
2190        with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
2191            list(p.glob(''))
2192
2193
2194@only_posix
2195class PosixPathTest(_BasePathTest, unittest.TestCase):
2196    cls = pathlib.PosixPath
2197
2198    def _check_symlink_loop(self, *args, strict=True):
2199        path = self.cls(*args)
2200        with self.assertRaises(RuntimeError):
2201            print(path.resolve(strict))
2202
2203    def test_open_mode(self):
2204        old_mask = os.umask(0)
2205        self.addCleanup(os.umask, old_mask)
2206        p = self.cls(BASE)
2207        with (p / 'new_file').open('wb'):
2208            pass
2209        st = os.stat(join('new_file'))
2210        self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
2211        os.umask(0o022)
2212        with (p / 'other_new_file').open('wb'):
2213            pass
2214        st = os.stat(join('other_new_file'))
2215        self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
2216
2217    def test_resolve_root(self):
2218        current_directory = os.getcwd()
2219        try:
2220            os.chdir('/')
2221            p = self.cls('spam')
2222            self.assertEqual(str(p.resolve()), '/spam')
2223        finally:
2224            os.chdir(current_directory)
2225
2226    def test_touch_mode(self):
2227        old_mask = os.umask(0)
2228        self.addCleanup(os.umask, old_mask)
2229        p = self.cls(BASE)
2230        (p / 'new_file').touch()
2231        st = os.stat(join('new_file'))
2232        self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
2233        os.umask(0o022)
2234        (p / 'other_new_file').touch()
2235        st = os.stat(join('other_new_file'))
2236        self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
2237        (p / 'masked_new_file').touch(mode=0o750)
2238        st = os.stat(join('masked_new_file'))
2239        self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
2240
2241    @support.skip_unless_symlink
2242    def test_resolve_loop(self):
2243        # Loops with relative symlinks.
2244        os.symlink('linkX/inside', join('linkX'))
2245        self._check_symlink_loop(BASE, 'linkX')
2246        os.symlink('linkY', join('linkY'))
2247        self._check_symlink_loop(BASE, 'linkY')
2248        os.symlink('linkZ/../linkZ', join('linkZ'))
2249        self._check_symlink_loop(BASE, 'linkZ')
2250        # Non-strict
2251        self._check_symlink_loop(BASE, 'linkZ', 'foo', strict=False)
2252        # Loops with absolute symlinks.
2253        os.symlink(join('linkU/inside'), join('linkU'))
2254        self._check_symlink_loop(BASE, 'linkU')
2255        os.symlink(join('linkV'), join('linkV'))
2256        self._check_symlink_loop(BASE, 'linkV')
2257        os.symlink(join('linkW/../linkW'), join('linkW'))
2258        self._check_symlink_loop(BASE, 'linkW')
2259        # Non-strict
2260        self._check_symlink_loop(BASE, 'linkW', 'foo', strict=False)
2261
2262    def test_glob(self):
2263        P = self.cls
2264        p = P(BASE)
2265        given = set(p.glob("FILEa"))
2266        expect = set() if not support.fs_is_case_insensitive(BASE) else given
2267        self.assertEqual(given, expect)
2268        self.assertEqual(set(p.glob("FILEa*")), set())
2269
2270    def test_rglob(self):
2271        P = self.cls
2272        p = P(BASE, "dirC")
2273        given = set(p.rglob("FILEd"))
2274        expect = set() if not support.fs_is_case_insensitive(BASE) else given
2275        self.assertEqual(given, expect)
2276        self.assertEqual(set(p.rglob("FILEd*")), set())
2277
2278    @unittest.skipUnless(hasattr(pwd, 'getpwall'),
2279                         'pwd module does not expose getpwall()')
2280    def test_expanduser(self):
2281        P = self.cls
2282        support.import_module('pwd')
2283        import pwd
2284        pwdent = pwd.getpwuid(os.getuid())
2285        username = pwdent.pw_name
2286        userhome = pwdent.pw_dir.rstrip('/') or '/'
2287        # Find arbitrary different user (if exists).
2288        for pwdent in pwd.getpwall():
2289            othername = pwdent.pw_name
2290            otherhome = pwdent.pw_dir.rstrip('/')
2291            if othername != username and otherhome:
2292                break
2293        else:
2294            othername = username
2295            otherhome = userhome
2296
2297        p1 = P('~/Documents')
2298        p2 = P('~' + username + '/Documents')
2299        p3 = P('~' + othername + '/Documents')
2300        p4 = P('../~' + username + '/Documents')
2301        p5 = P('/~' + username + '/Documents')
2302        p6 = P('')
2303        p7 = P('~fakeuser/Documents')
2304
2305        with support.EnvironmentVarGuard() as env:
2306            env.pop('HOME', None)
2307
2308            self.assertEqual(p1.expanduser(), P(userhome) / 'Documents')
2309            self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
2310            self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
2311            self.assertEqual(p4.expanduser(), p4)
2312            self.assertEqual(p5.expanduser(), p5)
2313            self.assertEqual(p6.expanduser(), p6)
2314            self.assertRaises(RuntimeError, p7.expanduser)
2315
2316            env['HOME'] = '/tmp'
2317            self.assertEqual(p1.expanduser(), P('/tmp/Documents'))
2318            self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
2319            self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
2320            self.assertEqual(p4.expanduser(), p4)
2321            self.assertEqual(p5.expanduser(), p5)
2322            self.assertEqual(p6.expanduser(), p6)
2323            self.assertRaises(RuntimeError, p7.expanduser)
2324
2325    @unittest.skipIf(sys.platform != "darwin",
2326                     "Bad file descriptor in /dev/fd affects only macOS")
2327    def test_handling_bad_descriptor(self):
2328        try:
2329            file_descriptors = list(pathlib.Path('/dev/fd').rglob("*"))[3:]
2330            if not file_descriptors:
2331                self.skipTest("no file descriptors - issue was not reproduced")
2332            # Checking all file descriptors because there is no guarantee
2333            # which one will fail.
2334            for f in file_descriptors:
2335                f.exists()
2336                f.is_dir()
2337                f.is_file()
2338                f.is_symlink()
2339                f.is_block_device()
2340                f.is_char_device()
2341                f.is_fifo()
2342                f.is_socket()
2343        except OSError as e:
2344            if e.errno == errno.EBADF:
2345                self.fail("Bad file descriptor not handled.")
2346            raise
2347
2348
2349@only_nt
2350class WindowsPathTest(_BasePathTest, unittest.TestCase):
2351    cls = pathlib.WindowsPath
2352
2353    def test_glob(self):
2354        P = self.cls
2355        p = P(BASE)
2356        self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
2357        self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") })
2358        self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"})
2359        self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"})
2360
2361    def test_rglob(self):
2362        P = self.cls
2363        p = P(BASE, "dirC")
2364        self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
2365        self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"})
2366
2367    def test_expanduser(self):
2368        P = self.cls
2369        with support.EnvironmentVarGuard() as env:
2370            env.pop('HOME', None)
2371            env.pop('USERPROFILE', None)
2372            env.pop('HOMEPATH', None)
2373            env.pop('HOMEDRIVE', None)
2374            env['USERNAME'] = 'alice'
2375
2376            # test that the path returns unchanged
2377            p1 = P('~/My Documents')
2378            p2 = P('~alice/My Documents')
2379            p3 = P('~bob/My Documents')
2380            p4 = P('/~/My Documents')
2381            p5 = P('d:~/My Documents')
2382            p6 = P('')
2383            self.assertRaises(RuntimeError, p1.expanduser)
2384            self.assertRaises(RuntimeError, p2.expanduser)
2385            self.assertRaises(RuntimeError, p3.expanduser)
2386            self.assertEqual(p4.expanduser(), p4)
2387            self.assertEqual(p5.expanduser(), p5)
2388            self.assertEqual(p6.expanduser(), p6)
2389
2390            def check():
2391                env.pop('USERNAME', None)
2392                self.assertEqual(p1.expanduser(),
2393                                 P('C:/Users/alice/My Documents'))
2394                self.assertRaises(KeyError, p2.expanduser)
2395                env['USERNAME'] = 'alice'
2396                self.assertEqual(p2.expanduser(),
2397                                 P('C:/Users/alice/My Documents'))
2398                self.assertEqual(p3.expanduser(),
2399                                 P('C:/Users/bob/My Documents'))
2400                self.assertEqual(p4.expanduser(), p4)
2401                self.assertEqual(p5.expanduser(), p5)
2402                self.assertEqual(p6.expanduser(), p6)
2403
2404            env['HOMEPATH'] = 'C:\\Users\\alice'
2405            check()
2406
2407            env['HOMEDRIVE'] = 'C:\\'
2408            env['HOMEPATH'] = 'Users\\alice'
2409            check()
2410
2411            env.pop('HOMEDRIVE', None)
2412            env.pop('HOMEPATH', None)
2413            env['USERPROFILE'] = 'C:\\Users\\alice'
2414            check()
2415
2416            # bpo-38883: ignore `HOME` when set on windows
2417            env['HOME'] = 'C:\\Users\\eve'
2418            check()
2419
2420
2421class CompatiblePathTest(unittest.TestCase):
2422    """
2423    Test that a type can be made compatible with PurePath
2424    derivatives by implementing division operator overloads.
2425    """
2426
2427    class CompatPath:
2428        """
2429        Minimum viable class to test PurePath compatibility.
2430        Simply uses the division operator to join a given
2431        string and the string value of another object with
2432        a forward slash.
2433        """
2434        def __init__(self, string):
2435            self.string = string
2436
2437        def __truediv__(self, other):
2438            return type(self)(f"{self.string}/{other}")
2439
2440        def __rtruediv__(self, other):
2441            return type(self)(f"{other}/{self.string}")
2442
2443    def test_truediv(self):
2444        result = pathlib.PurePath("test") / self.CompatPath("right")
2445        self.assertIsInstance(result, self.CompatPath)
2446        self.assertEqual(result.string, "test/right")
2447
2448        with self.assertRaises(TypeError):
2449            # Verify improper operations still raise a TypeError
2450            pathlib.PurePath("test") / 10
2451
2452    def test_rtruediv(self):
2453        result = self.CompatPath("left") / pathlib.PurePath("test")
2454        self.assertIsInstance(result, self.CompatPath)
2455        self.assertEqual(result.string, "left/test")
2456
2457        with self.assertRaises(TypeError):
2458            # Verify improper operations still raise a TypeError
2459            10 / pathlib.PurePath("test")
2460
2461
2462if __name__ == "__main__":
2463    unittest.main()
2464