• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        p = self.cls.home()
1300        self._test_home(p)
1301
1302    def test_samefile(self):
1303        fileA_path = os.path.join(BASE, 'fileA')
1304        fileB_path = os.path.join(BASE, 'dirB', 'fileB')
1305        p = self.cls(fileA_path)
1306        pp = self.cls(fileA_path)
1307        q = self.cls(fileB_path)
1308        self.assertTrue(p.samefile(fileA_path))
1309        self.assertTrue(p.samefile(pp))
1310        self.assertFalse(p.samefile(fileB_path))
1311        self.assertFalse(p.samefile(q))
1312        # Test the non-existent file case
1313        non_existent = os.path.join(BASE, 'foo')
1314        r = self.cls(non_existent)
1315        self.assertRaises(FileNotFoundError, p.samefile, r)
1316        self.assertRaises(FileNotFoundError, p.samefile, non_existent)
1317        self.assertRaises(FileNotFoundError, r.samefile, p)
1318        self.assertRaises(FileNotFoundError, r.samefile, non_existent)
1319        self.assertRaises(FileNotFoundError, r.samefile, r)
1320        self.assertRaises(FileNotFoundError, r.samefile, non_existent)
1321
1322    def test_empty_path(self):
1323        # The empty path points to '.'
1324        p = self.cls('')
1325        self.assertEqual(p.stat(), os.stat('.'))
1326
1327    def test_expanduser_common(self):
1328        P = self.cls
1329        p = P('~')
1330        self.assertEqual(p.expanduser(), P(os.path.expanduser('~')))
1331        p = P('foo')
1332        self.assertEqual(p.expanduser(), p)
1333        p = P('/~')
1334        self.assertEqual(p.expanduser(), p)
1335        p = P('../~')
1336        self.assertEqual(p.expanduser(), p)
1337        p = P(P('').absolute().anchor) / '~'
1338        self.assertEqual(p.expanduser(), p)
1339
1340    def test_exists(self):
1341        P = self.cls
1342        p = P(BASE)
1343        self.assertIs(True, p.exists())
1344        self.assertIs(True, (p / 'dirA').exists())
1345        self.assertIs(True, (p / 'fileA').exists())
1346        self.assertIs(False, (p / 'fileA' / 'bah').exists())
1347        if support.can_symlink():
1348            self.assertIs(True, (p / 'linkA').exists())
1349            self.assertIs(True, (p / 'linkB').exists())
1350            self.assertIs(True, (p / 'linkB' / 'fileB').exists())
1351            self.assertIs(False, (p / 'linkA' / 'bah').exists())
1352        self.assertIs(False, (p / 'foo').exists())
1353        self.assertIs(False, P('/xyzzy').exists())
1354        self.assertIs(False, P(BASE + '\udfff').exists())
1355        self.assertIs(False, P(BASE + '\x00').exists())
1356
1357    def test_open_common(self):
1358        p = self.cls(BASE)
1359        with (p / 'fileA').open('r') as f:
1360            self.assertIsInstance(f, io.TextIOBase)
1361            self.assertEqual(f.read(), "this is file A\n")
1362        with (p / 'fileA').open('rb') as f:
1363            self.assertIsInstance(f, io.BufferedIOBase)
1364            self.assertEqual(f.read().strip(), b"this is file A")
1365        with (p / 'fileA').open('rb', buffering=0) as f:
1366            self.assertIsInstance(f, io.RawIOBase)
1367            self.assertEqual(f.read().strip(), b"this is file A")
1368
1369    def test_read_write_bytes(self):
1370        p = self.cls(BASE)
1371        (p / 'fileA').write_bytes(b'abcdefg')
1372        self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
1373        # Check that trying to write str does not truncate the file.
1374        self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr')
1375        self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
1376
1377    def test_read_write_text(self):
1378        p = self.cls(BASE)
1379        (p / 'fileA').write_text('äbcdefg', encoding='latin-1')
1380        self.assertEqual((p / 'fileA').read_text(
1381            encoding='utf-8', errors='ignore'), 'bcdefg')
1382        # Check that trying to write bytes does not truncate the file.
1383        self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes')
1384        self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg')
1385
1386    def test_iterdir(self):
1387        P = self.cls
1388        p = P(BASE)
1389        it = p.iterdir()
1390        paths = set(it)
1391        expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
1392        if support.can_symlink():
1393            expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop']
1394        self.assertEqual(paths, { P(BASE, q) for q in expected })
1395
1396    @support.skip_unless_symlink
1397    def test_iterdir_symlink(self):
1398        # __iter__ on a symlink to a directory.
1399        P = self.cls
1400        p = P(BASE, 'linkB')
1401        paths = set(p.iterdir())
1402        expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] }
1403        self.assertEqual(paths, expected)
1404
1405    def test_iterdir_nodir(self):
1406        # __iter__ on something that is not a directory.
1407        p = self.cls(BASE, 'fileA')
1408        with self.assertRaises(OSError) as cm:
1409            next(p.iterdir())
1410        # ENOENT or EINVAL under Windows, ENOTDIR otherwise
1411        # (see issue #12802).
1412        self.assertIn(cm.exception.errno, (errno.ENOTDIR,
1413                                           errno.ENOENT, errno.EINVAL))
1414
1415    def test_glob_common(self):
1416        def _check(glob, expected):
1417            self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1418        P = self.cls
1419        p = P(BASE)
1420        it = p.glob("fileA")
1421        self.assertIsInstance(it, collections.abc.Iterator)
1422        _check(it, ["fileA"])
1423        _check(p.glob("fileB"), [])
1424        _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
1425        if not support.can_symlink():
1426            _check(p.glob("*A"), ['dirA', 'fileA'])
1427        else:
1428            _check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
1429        if not support.can_symlink():
1430            _check(p.glob("*B/*"), ['dirB/fileB'])
1431        else:
1432            _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
1433                                    'linkB/fileB', 'linkB/linkD'])
1434        if not support.can_symlink():
1435            _check(p.glob("*/fileB"), ['dirB/fileB'])
1436        else:
1437            _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1438
1439    def test_rglob_common(self):
1440        def _check(glob, expected):
1441            self.assertEqual(set(glob), { P(BASE, q) for q in expected })
1442        P = self.cls
1443        p = P(BASE)
1444        it = p.rglob("fileA")
1445        self.assertIsInstance(it, collections.abc.Iterator)
1446        _check(it, ["fileA"])
1447        _check(p.rglob("fileB"), ["dirB/fileB"])
1448        _check(p.rglob("*/fileA"), [])
1449        if not support.can_symlink():
1450            _check(p.rglob("*/fileB"), ["dirB/fileB"])
1451        else:
1452            _check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
1453                                        "linkB/fileB", "dirA/linkC/fileB"])
1454        _check(p.rglob("file*"), ["fileA", "dirB/fileB",
1455                                  "dirC/fileC", "dirC/dirD/fileD"])
1456        p = P(BASE, "dirC")
1457        _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1458        _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1459
1460    @support.skip_unless_symlink
1461    def test_rglob_symlink_loop(self):
1462        # Don't get fooled by symlink loops (Issue #26012).
1463        P = self.cls
1464        p = P(BASE)
1465        given = set(p.rglob('*'))
1466        expect = {'brokenLink',
1467                  'dirA', 'dirA/linkC',
1468                  'dirB', 'dirB/fileB', 'dirB/linkD',
1469                  'dirC', 'dirC/dirD', 'dirC/dirD/fileD', 'dirC/fileC',
1470                  'dirE',
1471                  'fileA',
1472                  'linkA',
1473                  'linkB',
1474                  'brokenLinkLoop',
1475                  }
1476        self.assertEqual(given, {p / x for x in expect})
1477
1478    def test_glob_many_open_files(self):
1479        depth = 30
1480        P = self.cls
1481        base = P(BASE) / 'deep'
1482        p = P(base, *(['d']*depth))
1483        p.mkdir(parents=True)
1484        pattern = '/'.join(['*'] * depth)
1485        iters = [base.glob(pattern) for j in range(100)]
1486        for it in iters:
1487            self.assertEqual(next(it), p)
1488        iters = [base.rglob('d') for j in range(100)]
1489        p = base
1490        for i in range(depth):
1491            p = p / 'd'
1492            for it in iters:
1493                self.assertEqual(next(it), p)
1494
1495    def test_glob_dotdot(self):
1496        # ".." is not special in globs.
1497        P = self.cls
1498        p = P(BASE)
1499        self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
1500        self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
1501        self.assertEqual(set(p.glob("../xyzzy")), set())
1502
1503
1504    def _check_resolve(self, p, expected, strict=True):
1505        q = p.resolve(strict)
1506        self.assertEqual(q, expected)
1507
1508    # This can be used to check both relative and absolute resolutions.
1509    _check_resolve_relative = _check_resolve_absolute = _check_resolve
1510
1511    @support.skip_unless_symlink
1512    def test_resolve_common(self):
1513        P = self.cls
1514        p = P(BASE, 'foo')
1515        with self.assertRaises(OSError) as cm:
1516            p.resolve(strict=True)
1517        self.assertEqual(cm.exception.errno, errno.ENOENT)
1518        # Non-strict
1519        self.assertEqualNormCase(str(p.resolve(strict=False)),
1520                                 os.path.join(BASE, 'foo'))
1521        p = P(BASE, 'foo', 'in', 'spam')
1522        self.assertEqualNormCase(str(p.resolve(strict=False)),
1523                                 os.path.join(BASE, 'foo', 'in', 'spam'))
1524        p = P(BASE, '..', 'foo', 'in', 'spam')
1525        self.assertEqualNormCase(str(p.resolve(strict=False)),
1526                                 os.path.abspath(os.path.join('foo', 'in', 'spam')))
1527        # These are all relative symlinks.
1528        p = P(BASE, 'dirB', 'fileB')
1529        self._check_resolve_relative(p, p)
1530        p = P(BASE, 'linkA')
1531        self._check_resolve_relative(p, P(BASE, 'fileA'))
1532        p = P(BASE, 'dirA', 'linkC', 'fileB')
1533        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1534        p = P(BASE, 'dirB', 'linkD', 'fileB')
1535        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
1536        # Non-strict
1537        p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
1538        self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo', 'in',
1539                                          'spam'), False)
1540        p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
1541        if os.name == 'nt':
1542            # In Windows, if linkY points to dirB, 'dirA\linkY\..'
1543            # resolves to 'dirA' without resolving linkY first.
1544            self._check_resolve_relative(p, P(BASE, 'dirA', 'foo', 'in',
1545                                              'spam'), False)
1546        else:
1547            # In Posix, if linkY points to dirB, 'dirA/linkY/..'
1548            # resolves to 'dirB/..' first before resolving to parent of dirB.
1549            self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
1550        # Now create absolute symlinks.
1551        d = support._longpath(tempfile.mkdtemp(suffix='-dirD', dir=os.getcwd()))
1552        self.addCleanup(support.rmtree, d)
1553        os.symlink(os.path.join(d), join('dirA', 'linkX'))
1554        os.symlink(join('dirB'), os.path.join(d, 'linkY'))
1555        p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB')
1556        self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
1557        # Non-strict
1558        p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
1559        self._check_resolve_relative(p, P(BASE, 'dirB', 'foo', 'in', 'spam'),
1560                                     False)
1561        p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
1562        if os.name == 'nt':
1563            # In Windows, if linkY points to dirB, 'dirA\linkY\..'
1564            # resolves to 'dirA' without resolving linkY first.
1565            self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
1566        else:
1567            # In Posix, if linkY points to dirB, 'dirA/linkY/..'
1568            # resolves to 'dirB/..' first before resolving to parent of dirB.
1569            self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
1570
1571    @support.skip_unless_symlink
1572    def test_resolve_dot(self):
1573        # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks
1574        p = self.cls(BASE)
1575        self.dirlink('.', join('0'))
1576        self.dirlink(os.path.join('0', '0'), join('1'))
1577        self.dirlink(os.path.join('1', '1'), join('2'))
1578        q = p / '2'
1579        self.assertEqual(q.resolve(strict=True), p)
1580        r = q / '3' / '4'
1581        self.assertRaises(FileNotFoundError, r.resolve, strict=True)
1582        # Non-strict
1583        self.assertEqual(r.resolve(strict=False), p / '3' / '4')
1584
1585    def test_with(self):
1586        p = self.cls(BASE)
1587        it = p.iterdir()
1588        it2 = p.iterdir()
1589        next(it2)
1590        with p:
1591            pass
1592        # I/O operation on closed path.
1593        self.assertRaises(ValueError, next, it)
1594        self.assertRaises(ValueError, next, it2)
1595        self.assertRaises(ValueError, p.open)
1596        self.assertRaises(ValueError, p.resolve)
1597        self.assertRaises(ValueError, p.absolute)
1598        self.assertRaises(ValueError, p.__enter__)
1599
1600    def test_chmod(self):
1601        p = self.cls(BASE) / 'fileA'
1602        mode = p.stat().st_mode
1603        # Clear writable bit.
1604        new_mode = mode & ~0o222
1605        p.chmod(new_mode)
1606        self.assertEqual(p.stat().st_mode, new_mode)
1607        # Set writable bit.
1608        new_mode = mode | 0o222
1609        p.chmod(new_mode)
1610        self.assertEqual(p.stat().st_mode, new_mode)
1611
1612    # XXX also need a test for lchmod.
1613
1614    def test_stat(self):
1615        p = self.cls(BASE) / 'fileA'
1616        st = p.stat()
1617        self.assertEqual(p.stat(), st)
1618        # Change file mode by flipping write bit.
1619        p.chmod(st.st_mode ^ 0o222)
1620        self.addCleanup(p.chmod, st.st_mode)
1621        self.assertNotEqual(p.stat(), st)
1622
1623    @support.skip_unless_symlink
1624    def test_lstat(self):
1625        p = self.cls(BASE)/ 'linkA'
1626        st = p.stat()
1627        self.assertNotEqual(st, p.lstat())
1628
1629    def test_lstat_nosymlink(self):
1630        p = self.cls(BASE) / 'fileA'
1631        st = p.stat()
1632        self.assertEqual(st, p.lstat())
1633
1634    @unittest.skipUnless(pwd, "the pwd module is needed for this test")
1635    def test_owner(self):
1636        p = self.cls(BASE) / 'fileA'
1637        uid = p.stat().st_uid
1638        try:
1639            name = pwd.getpwuid(uid).pw_name
1640        except KeyError:
1641            self.skipTest(
1642                "user %d doesn't have an entry in the system database" % uid)
1643        self.assertEqual(name, p.owner())
1644
1645    @unittest.skipUnless(grp, "the grp module is needed for this test")
1646    def test_group(self):
1647        p = self.cls(BASE) / 'fileA'
1648        gid = p.stat().st_gid
1649        try:
1650            name = grp.getgrgid(gid).gr_name
1651        except KeyError:
1652            self.skipTest(
1653                "group %d doesn't have an entry in the system database" % gid)
1654        self.assertEqual(name, p.group())
1655
1656    def test_unlink(self):
1657        p = self.cls(BASE) / 'fileA'
1658        p.unlink()
1659        self.assertFileNotFound(p.stat)
1660        self.assertFileNotFound(p.unlink)
1661
1662    def test_unlink_missing_ok(self):
1663        p = self.cls(BASE) / 'fileAAA'
1664        self.assertFileNotFound(p.unlink)
1665        p.unlink(missing_ok=True)
1666
1667    def test_rmdir(self):
1668        p = self.cls(BASE) / 'dirA'
1669        for q in p.iterdir():
1670            q.unlink()
1671        p.rmdir()
1672        self.assertFileNotFound(p.stat)
1673        self.assertFileNotFound(p.unlink)
1674
1675    @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present")
1676    def test_link_to(self):
1677        P = self.cls(BASE)
1678        p = P / 'fileA'
1679        size = p.stat().st_size
1680        # linking to another path.
1681        q = P / 'dirA' / 'fileAA'
1682        try:
1683            p.link_to(q)
1684        except PermissionError as e:
1685            self.skipTest('os.link(): %s' % e)
1686        self.assertEqual(q.stat().st_size, size)
1687        self.assertEqual(os.path.samefile(p, q), True)
1688        self.assertTrue(p.stat)
1689        # Linking to a str of a relative path.
1690        r = rel_join('fileAAA')
1691        q.link_to(r)
1692        self.assertEqual(os.stat(r).st_size, size)
1693        self.assertTrue(q.stat)
1694
1695    @unittest.skipIf(hasattr(os, "link"), "os.link() is present")
1696    def test_link_to_not_implemented(self):
1697        P = self.cls(BASE)
1698        p = P / 'fileA'
1699        # linking to another path.
1700        q = P / 'dirA' / 'fileAA'
1701        with self.assertRaises(NotImplementedError):
1702            p.link_to(q)
1703
1704    def test_rename(self):
1705        P = self.cls(BASE)
1706        p = P / 'fileA'
1707        size = p.stat().st_size
1708        # Renaming to another path.
1709        q = P / 'dirA' / 'fileAA'
1710        renamed_p = p.rename(q)
1711        self.assertEqual(renamed_p, q)
1712        self.assertEqual(q.stat().st_size, size)
1713        self.assertFileNotFound(p.stat)
1714        # Renaming to a str of a relative path.
1715        r = rel_join('fileAAA')
1716        renamed_q = q.rename(r)
1717        self.assertEqual(renamed_q, self.cls(r))
1718        self.assertEqual(os.stat(r).st_size, size)
1719        self.assertFileNotFound(q.stat)
1720
1721    def test_replace(self):
1722        P = self.cls(BASE)
1723        p = P / 'fileA'
1724        size = p.stat().st_size
1725        # Replacing a non-existing path.
1726        q = P / 'dirA' / 'fileAA'
1727        replaced_p = p.replace(q)
1728        self.assertEqual(replaced_p, q)
1729        self.assertEqual(q.stat().st_size, size)
1730        self.assertFileNotFound(p.stat)
1731        # Replacing another (existing) path.
1732        r = rel_join('dirB', 'fileB')
1733        replaced_q = q.replace(r)
1734        self.assertEqual(replaced_q, self.cls(r))
1735        self.assertEqual(os.stat(r).st_size, size)
1736        self.assertFileNotFound(q.stat)
1737
1738    def test_touch_common(self):
1739        P = self.cls(BASE)
1740        p = P / 'newfileA'
1741        self.assertFalse(p.exists())
1742        p.touch()
1743        self.assertTrue(p.exists())
1744        st = p.stat()
1745        old_mtime = st.st_mtime
1746        old_mtime_ns = st.st_mtime_ns
1747        # Rewind the mtime sufficiently far in the past to work around
1748        # filesystem-specific timestamp granularity.
1749        os.utime(str(p), (old_mtime - 10, old_mtime - 10))
1750        # The file mtime should be refreshed by calling touch() again.
1751        p.touch()
1752        st = p.stat()
1753        self.assertGreaterEqual(st.st_mtime_ns, old_mtime_ns)
1754        self.assertGreaterEqual(st.st_mtime, old_mtime)
1755        # Now with exist_ok=False.
1756        p = P / 'newfileB'
1757        self.assertFalse(p.exists())
1758        p.touch(mode=0o700, exist_ok=False)
1759        self.assertTrue(p.exists())
1760        self.assertRaises(OSError, p.touch, exist_ok=False)
1761
1762    def test_touch_nochange(self):
1763        P = self.cls(BASE)
1764        p = P / 'fileA'
1765        p.touch()
1766        with p.open('rb') as f:
1767            self.assertEqual(f.read().strip(), b"this is file A")
1768
1769    def test_mkdir(self):
1770        P = self.cls(BASE)
1771        p = P / 'newdirA'
1772        self.assertFalse(p.exists())
1773        p.mkdir()
1774        self.assertTrue(p.exists())
1775        self.assertTrue(p.is_dir())
1776        with self.assertRaises(OSError) as cm:
1777            p.mkdir()
1778        self.assertEqual(cm.exception.errno, errno.EEXIST)
1779
1780    def test_mkdir_parents(self):
1781        # Creating a chain of directories.
1782        p = self.cls(BASE, 'newdirB', 'newdirC')
1783        self.assertFalse(p.exists())
1784        with self.assertRaises(OSError) as cm:
1785            p.mkdir()
1786        self.assertEqual(cm.exception.errno, errno.ENOENT)
1787        p.mkdir(parents=True)
1788        self.assertTrue(p.exists())
1789        self.assertTrue(p.is_dir())
1790        with self.assertRaises(OSError) as cm:
1791            p.mkdir(parents=True)
1792        self.assertEqual(cm.exception.errno, errno.EEXIST)
1793        # Test `mode` arg.
1794        mode = stat.S_IMODE(p.stat().st_mode)  # Default mode.
1795        p = self.cls(BASE, 'newdirD', 'newdirE')
1796        p.mkdir(0o555, parents=True)
1797        self.assertTrue(p.exists())
1798        self.assertTrue(p.is_dir())
1799        if os.name != 'nt':
1800            # The directory's permissions follow the mode argument.
1801            self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode)
1802        # The parent's permissions follow the default process settings.
1803        self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
1804
1805    def test_mkdir_exist_ok(self):
1806        p = self.cls(BASE, 'dirB')
1807        st_ctime_first = p.stat().st_ctime
1808        self.assertTrue(p.exists())
1809        self.assertTrue(p.is_dir())
1810        with self.assertRaises(FileExistsError) as cm:
1811            p.mkdir()
1812        self.assertEqual(cm.exception.errno, errno.EEXIST)
1813        p.mkdir(exist_ok=True)
1814        self.assertTrue(p.exists())
1815        self.assertEqual(p.stat().st_ctime, st_ctime_first)
1816
1817    def test_mkdir_exist_ok_with_parent(self):
1818        p = self.cls(BASE, 'dirC')
1819        self.assertTrue(p.exists())
1820        with self.assertRaises(FileExistsError) as cm:
1821            p.mkdir()
1822        self.assertEqual(cm.exception.errno, errno.EEXIST)
1823        p = p / 'newdirC'
1824        p.mkdir(parents=True)
1825        st_ctime_first = p.stat().st_ctime
1826        self.assertTrue(p.exists())
1827        with self.assertRaises(FileExistsError) as cm:
1828            p.mkdir(parents=True)
1829        self.assertEqual(cm.exception.errno, errno.EEXIST)
1830        p.mkdir(parents=True, exist_ok=True)
1831        self.assertTrue(p.exists())
1832        self.assertEqual(p.stat().st_ctime, st_ctime_first)
1833
1834    def test_mkdir_exist_ok_root(self):
1835        # Issue #25803: A drive root could raise PermissionError on Windows.
1836        self.cls('/').resolve().mkdir(exist_ok=True)
1837        self.cls('/').resolve().mkdir(parents=True, exist_ok=True)
1838
1839    @only_nt  # XXX: not sure how to test this on POSIX.
1840    def test_mkdir_with_unknown_drive(self):
1841        for d in 'ZYXWVUTSRQPONMLKJIHGFEDCBA':
1842            p = self.cls(d + ':\\')
1843            if not p.is_dir():
1844                break
1845        else:
1846            self.skipTest("cannot find a drive that doesn't exist")
1847        with self.assertRaises(OSError):
1848            (p / 'child' / 'path').mkdir(parents=True)
1849
1850    def test_mkdir_with_child_file(self):
1851        p = self.cls(BASE, 'dirB', 'fileB')
1852        self.assertTrue(p.exists())
1853        # An exception is raised when the last path component is an existing
1854        # regular file, regardless of whether exist_ok is true or not.
1855        with self.assertRaises(FileExistsError) as cm:
1856            p.mkdir(parents=True)
1857        self.assertEqual(cm.exception.errno, errno.EEXIST)
1858        with self.assertRaises(FileExistsError) as cm:
1859            p.mkdir(parents=True, exist_ok=True)
1860        self.assertEqual(cm.exception.errno, errno.EEXIST)
1861
1862    def test_mkdir_no_parents_file(self):
1863        p = self.cls(BASE, 'fileA')
1864        self.assertTrue(p.exists())
1865        # An exception is raised when the last path component is an existing
1866        # regular file, regardless of whether exist_ok is true or not.
1867        with self.assertRaises(FileExistsError) as cm:
1868            p.mkdir()
1869        self.assertEqual(cm.exception.errno, errno.EEXIST)
1870        with self.assertRaises(FileExistsError) as cm:
1871            p.mkdir(exist_ok=True)
1872        self.assertEqual(cm.exception.errno, errno.EEXIST)
1873
1874    def test_mkdir_concurrent_parent_creation(self):
1875        for pattern_num in range(32):
1876            p = self.cls(BASE, 'dirCPC%d' % pattern_num)
1877            self.assertFalse(p.exists())
1878
1879            def my_mkdir(path, mode=0o777):
1880                path = str(path)
1881                # Emulate another process that would create the directory
1882                # just before we try to create it ourselves.  We do it
1883                # in all possible pattern combinations, assuming that this
1884                # function is called at most 5 times (dirCPC/dir1/dir2,
1885                # dirCPC/dir1, dirCPC, dirCPC/dir1, dirCPC/dir1/dir2).
1886                if pattern.pop():
1887                    os.mkdir(path, mode)  # From another process.
1888                    concurrently_created.add(path)
1889                os.mkdir(path, mode)  # Our real call.
1890
1891            pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
1892            concurrently_created = set()
1893            p12 = p / 'dir1' / 'dir2'
1894            try:
1895                with mock.patch("pathlib._normal_accessor.mkdir", my_mkdir):
1896                    p12.mkdir(parents=True, exist_ok=False)
1897            except FileExistsError:
1898                self.assertIn(str(p12), concurrently_created)
1899            else:
1900                self.assertNotIn(str(p12), concurrently_created)
1901            self.assertTrue(p.exists())
1902
1903    @support.skip_unless_symlink
1904    def test_symlink_to(self):
1905        P = self.cls(BASE)
1906        target = P / 'fileA'
1907        # Symlinking a path target.
1908        link = P / 'dirA' / 'linkAA'
1909        link.symlink_to(target)
1910        self.assertEqual(link.stat(), target.stat())
1911        self.assertNotEqual(link.lstat(), target.stat())
1912        # Symlinking a str target.
1913        link = P / 'dirA' / 'linkAAA'
1914        link.symlink_to(str(target))
1915        self.assertEqual(link.stat(), target.stat())
1916        self.assertNotEqual(link.lstat(), target.stat())
1917        self.assertFalse(link.is_dir())
1918        # Symlinking to a directory.
1919        target = P / 'dirB'
1920        link = P / 'dirA' / 'linkAAAA'
1921        link.symlink_to(target, target_is_directory=True)
1922        self.assertEqual(link.stat(), target.stat())
1923        self.assertNotEqual(link.lstat(), target.stat())
1924        self.assertTrue(link.is_dir())
1925        self.assertTrue(list(link.iterdir()))
1926
1927    def test_is_dir(self):
1928        P = self.cls(BASE)
1929        self.assertTrue((P / 'dirA').is_dir())
1930        self.assertFalse((P / 'fileA').is_dir())
1931        self.assertFalse((P / 'non-existing').is_dir())
1932        self.assertFalse((P / 'fileA' / 'bah').is_dir())
1933        if support.can_symlink():
1934            self.assertFalse((P / 'linkA').is_dir())
1935            self.assertTrue((P / 'linkB').is_dir())
1936            self.assertFalse((P/ 'brokenLink').is_dir(), False)
1937        self.assertIs((P / 'dirA\udfff').is_dir(), False)
1938        self.assertIs((P / 'dirA\x00').is_dir(), False)
1939
1940    def test_is_file(self):
1941        P = self.cls(BASE)
1942        self.assertTrue((P / 'fileA').is_file())
1943        self.assertFalse((P / 'dirA').is_file())
1944        self.assertFalse((P / 'non-existing').is_file())
1945        self.assertFalse((P / 'fileA' / 'bah').is_file())
1946        if support.can_symlink():
1947            self.assertTrue((P / 'linkA').is_file())
1948            self.assertFalse((P / 'linkB').is_file())
1949            self.assertFalse((P/ 'brokenLink').is_file())
1950        self.assertIs((P / 'fileA\udfff').is_file(), False)
1951        self.assertIs((P / 'fileA\x00').is_file(), False)
1952
1953    @only_posix
1954    def test_is_mount(self):
1955        P = self.cls(BASE)
1956        R = self.cls('/')  # TODO: Work out Windows.
1957        self.assertFalse((P / 'fileA').is_mount())
1958        self.assertFalse((P / 'dirA').is_mount())
1959        self.assertFalse((P / 'non-existing').is_mount())
1960        self.assertFalse((P / 'fileA' / 'bah').is_mount())
1961        self.assertTrue(R.is_mount())
1962        if support.can_symlink():
1963            self.assertFalse((P / 'linkA').is_mount())
1964        self.assertIs(self.cls('/\udfff').is_mount(), False)
1965        self.assertIs(self.cls('/\x00').is_mount(), False)
1966
1967    def test_is_symlink(self):
1968        P = self.cls(BASE)
1969        self.assertFalse((P / 'fileA').is_symlink())
1970        self.assertFalse((P / 'dirA').is_symlink())
1971        self.assertFalse((P / 'non-existing').is_symlink())
1972        self.assertFalse((P / 'fileA' / 'bah').is_symlink())
1973        if support.can_symlink():
1974            self.assertTrue((P / 'linkA').is_symlink())
1975            self.assertTrue((P / 'linkB').is_symlink())
1976            self.assertTrue((P/ 'brokenLink').is_symlink())
1977        self.assertIs((P / 'fileA\udfff').is_file(), False)
1978        self.assertIs((P / 'fileA\x00').is_file(), False)
1979        if support.can_symlink():
1980            self.assertIs((P / 'linkA\udfff').is_file(), False)
1981            self.assertIs((P / 'linkA\x00').is_file(), False)
1982
1983    def test_is_fifo_false(self):
1984        P = self.cls(BASE)
1985        self.assertFalse((P / 'fileA').is_fifo())
1986        self.assertFalse((P / 'dirA').is_fifo())
1987        self.assertFalse((P / 'non-existing').is_fifo())
1988        self.assertFalse((P / 'fileA' / 'bah').is_fifo())
1989        self.assertIs((P / 'fileA\udfff').is_fifo(), False)
1990        self.assertIs((P / 'fileA\x00').is_fifo(), False)
1991
1992    @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required")
1993    def test_is_fifo_true(self):
1994        P = self.cls(BASE, 'myfifo')
1995        try:
1996            os.mkfifo(str(P))
1997        except PermissionError as e:
1998            self.skipTest('os.mkfifo(): %s' % e)
1999        self.assertTrue(P.is_fifo())
2000        self.assertFalse(P.is_socket())
2001        self.assertFalse(P.is_file())
2002        self.assertIs(self.cls(BASE, 'myfifo\udfff').is_fifo(), False)
2003        self.assertIs(self.cls(BASE, 'myfifo\x00').is_fifo(), False)
2004
2005    def test_is_socket_false(self):
2006        P = self.cls(BASE)
2007        self.assertFalse((P / 'fileA').is_socket())
2008        self.assertFalse((P / 'dirA').is_socket())
2009        self.assertFalse((P / 'non-existing').is_socket())
2010        self.assertFalse((P / 'fileA' / 'bah').is_socket())
2011        self.assertIs((P / 'fileA\udfff').is_socket(), False)
2012        self.assertIs((P / 'fileA\x00').is_socket(), False)
2013
2014    @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
2015    def test_is_socket_true(self):
2016        P = self.cls(BASE, 'mysock')
2017        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
2018        self.addCleanup(sock.close)
2019        try:
2020            sock.bind(str(P))
2021        except OSError as e:
2022            if (isinstance(e, PermissionError) or
2023                    "AF_UNIX path too long" in str(e)):
2024                self.skipTest("cannot bind Unix socket: " + str(e))
2025        self.assertTrue(P.is_socket())
2026        self.assertFalse(P.is_fifo())
2027        self.assertFalse(P.is_file())
2028        self.assertIs(self.cls(BASE, 'mysock\udfff').is_socket(), False)
2029        self.assertIs(self.cls(BASE, 'mysock\x00').is_socket(), False)
2030
2031    def test_is_block_device_false(self):
2032        P = self.cls(BASE)
2033        self.assertFalse((P / 'fileA').is_block_device())
2034        self.assertFalse((P / 'dirA').is_block_device())
2035        self.assertFalse((P / 'non-existing').is_block_device())
2036        self.assertFalse((P / 'fileA' / 'bah').is_block_device())
2037        self.assertIs((P / 'fileA\udfff').is_block_device(), False)
2038        self.assertIs((P / 'fileA\x00').is_block_device(), False)
2039
2040    def test_is_char_device_false(self):
2041        P = self.cls(BASE)
2042        self.assertFalse((P / 'fileA').is_char_device())
2043        self.assertFalse((P / 'dirA').is_char_device())
2044        self.assertFalse((P / 'non-existing').is_char_device())
2045        self.assertFalse((P / 'fileA' / 'bah').is_char_device())
2046        self.assertIs((P / 'fileA\udfff').is_char_device(), False)
2047        self.assertIs((P / 'fileA\x00').is_char_device(), False)
2048
2049    def test_is_char_device_true(self):
2050        # Under Unix, /dev/null should generally be a char device.
2051        P = self.cls('/dev/null')
2052        if not P.exists():
2053            self.skipTest("/dev/null required")
2054        self.assertTrue(P.is_char_device())
2055        self.assertFalse(P.is_block_device())
2056        self.assertFalse(P.is_file())
2057        self.assertIs(self.cls('/dev/null\udfff').is_char_device(), False)
2058        self.assertIs(self.cls('/dev/null\x00').is_char_device(), False)
2059
2060    def test_pickling_common(self):
2061        p = self.cls(BASE, 'fileA')
2062        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
2063            dumped = pickle.dumps(p, proto)
2064            pp = pickle.loads(dumped)
2065            self.assertEqual(pp.stat(), p.stat())
2066
2067    def test_parts_interning(self):
2068        P = self.cls
2069        p = P('/usr/bin/foo')
2070        q = P('/usr/local/bin')
2071        # 'usr'
2072        self.assertIs(p.parts[1], q.parts[1])
2073        # 'bin'
2074        self.assertIs(p.parts[2], q.parts[3])
2075
2076    def _check_complex_symlinks(self, link0_target):
2077        # Test solving a non-looping chain of symlinks (issue #19887).
2078        P = self.cls(BASE)
2079        self.dirlink(os.path.join('link0', 'link0'), join('link1'))
2080        self.dirlink(os.path.join('link1', 'link1'), join('link2'))
2081        self.dirlink(os.path.join('link2', 'link2'), join('link3'))
2082        self.dirlink(link0_target, join('link0'))
2083
2084        # Resolve absolute paths.
2085        p = (P / 'link0').resolve()
2086        self.assertEqual(p, P)
2087        self.assertEqualNormCase(str(p), BASE)
2088        p = (P / 'link1').resolve()
2089        self.assertEqual(p, P)
2090        self.assertEqualNormCase(str(p), BASE)
2091        p = (P / 'link2').resolve()
2092        self.assertEqual(p, P)
2093        self.assertEqualNormCase(str(p), BASE)
2094        p = (P / 'link3').resolve()
2095        self.assertEqual(p, P)
2096        self.assertEqualNormCase(str(p), BASE)
2097
2098        # Resolve relative paths.
2099        old_path = os.getcwd()
2100        os.chdir(BASE)
2101        try:
2102            p = self.cls('link0').resolve()
2103            self.assertEqual(p, P)
2104            self.assertEqualNormCase(str(p), BASE)
2105            p = self.cls('link1').resolve()
2106            self.assertEqual(p, P)
2107            self.assertEqualNormCase(str(p), BASE)
2108            p = self.cls('link2').resolve()
2109            self.assertEqual(p, P)
2110            self.assertEqualNormCase(str(p), BASE)
2111            p = self.cls('link3').resolve()
2112            self.assertEqual(p, P)
2113            self.assertEqualNormCase(str(p), BASE)
2114        finally:
2115            os.chdir(old_path)
2116
2117    @support.skip_unless_symlink
2118    def test_complex_symlinks_absolute(self):
2119        self._check_complex_symlinks(BASE)
2120
2121    @support.skip_unless_symlink
2122    def test_complex_symlinks_relative(self):
2123        self._check_complex_symlinks('.')
2124
2125    @support.skip_unless_symlink
2126    def test_complex_symlinks_relative_dot_dot(self):
2127        self._check_complex_symlinks(os.path.join('dirA', '..'))
2128
2129
2130class PathTest(_BasePathTest, unittest.TestCase):
2131    cls = pathlib.Path
2132
2133    def test_concrete_class(self):
2134        p = self.cls('a')
2135        self.assertIs(type(p),
2136            pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath)
2137
2138    def test_unsupported_flavour(self):
2139        if os.name == 'nt':
2140            self.assertRaises(NotImplementedError, pathlib.PosixPath)
2141        else:
2142            self.assertRaises(NotImplementedError, pathlib.WindowsPath)
2143
2144    def test_glob_empty_pattern(self):
2145        p = self.cls()
2146        with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
2147            list(p.glob(''))
2148
2149
2150@only_posix
2151class PosixPathTest(_BasePathTest, unittest.TestCase):
2152    cls = pathlib.PosixPath
2153
2154    def _check_symlink_loop(self, *args, strict=True):
2155        path = self.cls(*args)
2156        with self.assertRaises(RuntimeError):
2157            print(path.resolve(strict))
2158
2159    def test_open_mode(self):
2160        old_mask = os.umask(0)
2161        self.addCleanup(os.umask, old_mask)
2162        p = self.cls(BASE)
2163        with (p / 'new_file').open('wb'):
2164            pass
2165        st = os.stat(join('new_file'))
2166        self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
2167        os.umask(0o022)
2168        with (p / 'other_new_file').open('wb'):
2169            pass
2170        st = os.stat(join('other_new_file'))
2171        self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
2172
2173    def test_touch_mode(self):
2174        old_mask = os.umask(0)
2175        self.addCleanup(os.umask, old_mask)
2176        p = self.cls(BASE)
2177        (p / 'new_file').touch()
2178        st = os.stat(join('new_file'))
2179        self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
2180        os.umask(0o022)
2181        (p / 'other_new_file').touch()
2182        st = os.stat(join('other_new_file'))
2183        self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
2184        (p / 'masked_new_file').touch(mode=0o750)
2185        st = os.stat(join('masked_new_file'))
2186        self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
2187
2188    @support.skip_unless_symlink
2189    def test_resolve_loop(self):
2190        # Loops with relative symlinks.
2191        os.symlink('linkX/inside', join('linkX'))
2192        self._check_symlink_loop(BASE, 'linkX')
2193        os.symlink('linkY', join('linkY'))
2194        self._check_symlink_loop(BASE, 'linkY')
2195        os.symlink('linkZ/../linkZ', join('linkZ'))
2196        self._check_symlink_loop(BASE, 'linkZ')
2197        # Non-strict
2198        self._check_symlink_loop(BASE, 'linkZ', 'foo', strict=False)
2199        # Loops with absolute symlinks.
2200        os.symlink(join('linkU/inside'), join('linkU'))
2201        self._check_symlink_loop(BASE, 'linkU')
2202        os.symlink(join('linkV'), join('linkV'))
2203        self._check_symlink_loop(BASE, 'linkV')
2204        os.symlink(join('linkW/../linkW'), join('linkW'))
2205        self._check_symlink_loop(BASE, 'linkW')
2206        # Non-strict
2207        self._check_symlink_loop(BASE, 'linkW', 'foo', strict=False)
2208
2209    def test_glob(self):
2210        P = self.cls
2211        p = P(BASE)
2212        given = set(p.glob("FILEa"))
2213        expect = set() if not support.fs_is_case_insensitive(BASE) else given
2214        self.assertEqual(given, expect)
2215        self.assertEqual(set(p.glob("FILEa*")), set())
2216
2217    def test_rglob(self):
2218        P = self.cls
2219        p = P(BASE, "dirC")
2220        given = set(p.rglob("FILEd"))
2221        expect = set() if not support.fs_is_case_insensitive(BASE) else given
2222        self.assertEqual(given, expect)
2223        self.assertEqual(set(p.rglob("FILEd*")), set())
2224
2225    @unittest.skipUnless(hasattr(pwd, 'getpwall'),
2226                         'pwd module does not expose getpwall()')
2227    def test_expanduser(self):
2228        P = self.cls
2229        support.import_module('pwd')
2230        import pwd
2231        pwdent = pwd.getpwuid(os.getuid())
2232        username = pwdent.pw_name
2233        userhome = pwdent.pw_dir.rstrip('/') or '/'
2234        # Find arbitrary different user (if exists).
2235        for pwdent in pwd.getpwall():
2236            othername = pwdent.pw_name
2237            otherhome = pwdent.pw_dir.rstrip('/')
2238            if othername != username and otherhome:
2239                break
2240        else:
2241            othername = username
2242            otherhome = userhome
2243
2244        p1 = P('~/Documents')
2245        p2 = P('~' + username + '/Documents')
2246        p3 = P('~' + othername + '/Documents')
2247        p4 = P('../~' + username + '/Documents')
2248        p5 = P('/~' + username + '/Documents')
2249        p6 = P('')
2250        p7 = P('~fakeuser/Documents')
2251
2252        with support.EnvironmentVarGuard() as env:
2253            env.pop('HOME', None)
2254
2255            self.assertEqual(p1.expanduser(), P(userhome) / 'Documents')
2256            self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
2257            self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
2258            self.assertEqual(p4.expanduser(), p4)
2259            self.assertEqual(p5.expanduser(), p5)
2260            self.assertEqual(p6.expanduser(), p6)
2261            self.assertRaises(RuntimeError, p7.expanduser)
2262
2263            env['HOME'] = '/tmp'
2264            self.assertEqual(p1.expanduser(), P('/tmp/Documents'))
2265            self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
2266            self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
2267            self.assertEqual(p4.expanduser(), p4)
2268            self.assertEqual(p5.expanduser(), p5)
2269            self.assertEqual(p6.expanduser(), p6)
2270            self.assertRaises(RuntimeError, p7.expanduser)
2271
2272    @unittest.skipIf(sys.platform != "darwin",
2273                     "Bad file descriptor in /dev/fd affects only macOS")
2274    def test_handling_bad_descriptor(self):
2275        try:
2276            file_descriptors = list(pathlib.Path('/dev/fd').rglob("*"))[3:]
2277            if not file_descriptors:
2278                self.skipTest("no file descriptors - issue was not reproduced")
2279            # Checking all file descriptors because there is no guarantee
2280            # which one will fail.
2281            for f in file_descriptors:
2282                f.exists()
2283                f.is_dir()
2284                f.is_file()
2285                f.is_symlink()
2286                f.is_block_device()
2287                f.is_char_device()
2288                f.is_fifo()
2289                f.is_socket()
2290        except OSError as e:
2291            if e.errno == errno.EBADF:
2292                self.fail("Bad file descriptor not handled.")
2293            raise
2294
2295
2296@only_nt
2297class WindowsPathTest(_BasePathTest, unittest.TestCase):
2298    cls = pathlib.WindowsPath
2299
2300    def test_glob(self):
2301        P = self.cls
2302        p = P(BASE)
2303        self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
2304        self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") })
2305        self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"})
2306        self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"})
2307
2308    def test_rglob(self):
2309        P = self.cls
2310        p = P(BASE, "dirC")
2311        self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
2312        self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"})
2313
2314    def test_expanduser(self):
2315        P = self.cls
2316        with support.EnvironmentVarGuard() as env:
2317            env.pop('HOME', None)
2318            env.pop('USERPROFILE', None)
2319            env.pop('HOMEPATH', None)
2320            env.pop('HOMEDRIVE', None)
2321            env['USERNAME'] = 'alice'
2322
2323            # test that the path returns unchanged
2324            p1 = P('~/My Documents')
2325            p2 = P('~alice/My Documents')
2326            p3 = P('~bob/My Documents')
2327            p4 = P('/~/My Documents')
2328            p5 = P('d:~/My Documents')
2329            p6 = P('')
2330            self.assertRaises(RuntimeError, p1.expanduser)
2331            self.assertRaises(RuntimeError, p2.expanduser)
2332            self.assertRaises(RuntimeError, p3.expanduser)
2333            self.assertEqual(p4.expanduser(), p4)
2334            self.assertEqual(p5.expanduser(), p5)
2335            self.assertEqual(p6.expanduser(), p6)
2336
2337            def check():
2338                env.pop('USERNAME', None)
2339                self.assertEqual(p1.expanduser(),
2340                                 P('C:/Users/alice/My Documents'))
2341                self.assertRaises(KeyError, p2.expanduser)
2342                env['USERNAME'] = 'alice'
2343                self.assertEqual(p2.expanduser(),
2344                                 P('C:/Users/alice/My Documents'))
2345                self.assertEqual(p3.expanduser(),
2346                                 P('C:/Users/bob/My Documents'))
2347                self.assertEqual(p4.expanduser(), p4)
2348                self.assertEqual(p5.expanduser(), p5)
2349                self.assertEqual(p6.expanduser(), p6)
2350
2351            # Test the first lookup key in the env vars.
2352            env['HOME'] = 'C:\\Users\\alice'
2353            check()
2354
2355            # Test that HOMEPATH is available instead.
2356            env.pop('HOME', None)
2357            env['HOMEPATH'] = 'C:\\Users\\alice'
2358            check()
2359
2360            env['HOMEDRIVE'] = 'C:\\'
2361            env['HOMEPATH'] = 'Users\\alice'
2362            check()
2363
2364            env.pop('HOMEDRIVE', None)
2365            env.pop('HOMEPATH', None)
2366            env['USERPROFILE'] = 'C:\\Users\\alice'
2367            check()
2368
2369
2370class CompatiblePathTest(unittest.TestCase):
2371    """
2372    Test that a type can be made compatible with PurePath
2373    derivatives by implementing division operator overloads.
2374    """
2375
2376    class CompatPath:
2377        """
2378        Minimum viable class to test PurePath compatibility.
2379        Simply uses the division operator to join a given
2380        string and the string value of another object with
2381        a forward slash.
2382        """
2383        def __init__(self, string):
2384            self.string = string
2385
2386        def __truediv__(self, other):
2387            return type(self)(f"{self.string}/{other}")
2388
2389        def __rtruediv__(self, other):
2390            return type(self)(f"{other}/{self.string}")
2391
2392    def test_truediv(self):
2393        result = pathlib.PurePath("test") / self.CompatPath("right")
2394        self.assertIsInstance(result, self.CompatPath)
2395        self.assertEqual(result.string, "test/right")
2396
2397        with self.assertRaises(TypeError):
2398            # Verify improper operations still raise a TypeError
2399            pathlib.PurePath("test") / 10
2400
2401    def test_rtruediv(self):
2402        result = self.CompatPath("left") / pathlib.PurePath("test")
2403        self.assertIsInstance(result, self.CompatPath)
2404        self.assertEqual(result.string, "left/test")
2405
2406        with self.assertRaises(TypeError):
2407            # Verify improper operations still raise a TypeError
2408            10 / pathlib.PurePath("test")
2409
2410
2411if __name__ == "__main__":
2412    unittest.main()
2413