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