1import ntpath
2import os
3import string
4import sys
5import unittest
6import warnings
7from test.support import os_helper
8from test.support import TestFailed, is_emscripten
9from test.support.os_helper import FakePath
10from test import test_genericpath
11from tempfile import TemporaryFile
12
13
14try:
15    import nt
16except ImportError:
17    # Most tests can complete without the nt module,
18    # but for those that require it we import here.
19    nt = None
20
21try:
22    ntpath._getfinalpathname
23except AttributeError:
24    HAVE_GETFINALPATHNAME = False
25else:
26    HAVE_GETFINALPATHNAME = True
27
28try:
29    import ctypes
30except ImportError:
31    HAVE_GETSHORTPATHNAME = False
32else:
33    HAVE_GETSHORTPATHNAME = True
34    def _getshortpathname(path):
35        GSPN = ctypes.WinDLL("kernel32", use_last_error=True).GetShortPathNameW
36        GSPN.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32]
37        GSPN.restype = ctypes.c_uint32
38        result_len = GSPN(path, None, 0)
39        if not result_len:
40            raise OSError("failed to get short path name 0x{:08X}"
41                          .format(ctypes.get_last_error()))
42        result = ctypes.create_unicode_buffer(result_len)
43        result_len = GSPN(path, result, result_len)
44        return result[:result_len]
45
46def _norm(path):
47    if isinstance(path, (bytes, str, os.PathLike)):
48        return ntpath.normcase(os.fsdecode(path))
49    elif hasattr(path, "__iter__"):
50        return tuple(ntpath.normcase(os.fsdecode(p)) for p in path)
51    return path
52
53
54def tester(fn, wantResult):
55    fn = fn.replace("\\", "\\\\")
56    gotResult = eval(fn)
57    if wantResult != gotResult and _norm(wantResult) != _norm(gotResult):
58        raise TestFailed("%s should return: %s but returned: %s" \
59              %(str(fn), str(wantResult), str(gotResult)))
60
61    # then with bytes
62    fn = fn.replace("('", "(b'")
63    fn = fn.replace('("', '(b"')
64    fn = fn.replace("['", "[b'")
65    fn = fn.replace('["', '[b"')
66    fn = fn.replace(", '", ", b'")
67    fn = fn.replace(', "', ', b"')
68    fn = os.fsencode(fn).decode('latin1')
69    fn = fn.encode('ascii', 'backslashreplace').decode('ascii')
70    with warnings.catch_warnings():
71        warnings.simplefilter("ignore", DeprecationWarning)
72        gotResult = eval(fn)
73    if _norm(wantResult) != _norm(gotResult):
74        raise TestFailed("%s should return: %s but returned: %s" \
75              %(str(fn), str(wantResult), repr(gotResult)))
76
77
78class NtpathTestCase(unittest.TestCase):
79    def assertPathEqual(self, path1, path2):
80        if path1 == path2 or _norm(path1) == _norm(path2):
81            return
82        self.assertEqual(path1, path2)
83
84    def assertPathIn(self, path, pathset):
85        self.assertIn(_norm(path), _norm(pathset))
86
87
88class TestNtpath(NtpathTestCase):
89    def test_splitext(self):
90        tester('ntpath.splitext("foo.ext")', ('foo', '.ext'))
91        tester('ntpath.splitext("/foo/foo.ext")', ('/foo/foo', '.ext'))
92        tester('ntpath.splitext(".ext")', ('.ext', ''))
93        tester('ntpath.splitext("\\foo.ext\\foo")', ('\\foo.ext\\foo', ''))
94        tester('ntpath.splitext("foo.ext\\")', ('foo.ext\\', ''))
95        tester('ntpath.splitext("")', ('', ''))
96        tester('ntpath.splitext("foo.bar.ext")', ('foo.bar', '.ext'))
97        tester('ntpath.splitext("xx/foo.bar.ext")', ('xx/foo.bar', '.ext'))
98        tester('ntpath.splitext("xx\\foo.bar.ext")', ('xx\\foo.bar', '.ext'))
99        tester('ntpath.splitext("c:a/b\\c.d")', ('c:a/b\\c', '.d'))
100
101    def test_splitdrive(self):
102        tester('ntpath.splitdrive("c:\\foo\\bar")',
103               ('c:', '\\foo\\bar'))
104        tester('ntpath.splitdrive("c:/foo/bar")',
105               ('c:', '/foo/bar'))
106        tester('ntpath.splitdrive("\\\\conky\\mountpoint\\foo\\bar")',
107               ('\\\\conky\\mountpoint', '\\foo\\bar'))
108        tester('ntpath.splitdrive("//conky/mountpoint/foo/bar")',
109               ('//conky/mountpoint', '/foo/bar'))
110        tester('ntpath.splitdrive("\\\\\\conky\\mountpoint\\foo\\bar")',
111            ('\\\\\\conky', '\\mountpoint\\foo\\bar'))
112        tester('ntpath.splitdrive("///conky/mountpoint/foo/bar")',
113            ('///conky', '/mountpoint/foo/bar'))
114        tester('ntpath.splitdrive("\\\\conky\\\\mountpoint\\foo\\bar")',
115               ('\\\\conky\\', '\\mountpoint\\foo\\bar'))
116        tester('ntpath.splitdrive("//conky//mountpoint/foo/bar")',
117               ('//conky/', '/mountpoint/foo/bar'))
118        # Issue #19911: UNC part containing U+0130
119        self.assertEqual(ntpath.splitdrive('//conky/MOUNTPOİNT/foo/bar'),
120                         ('//conky/MOUNTPOİNT', '/foo/bar'))
121
122        # gh-81790: support device namespace, including UNC drives.
123        tester('ntpath.splitdrive("//?/c:")', ("//?/c:", ""))
124        tester('ntpath.splitdrive("//?/c:/")', ("//?/c:", "/"))
125        tester('ntpath.splitdrive("//?/c:/dir")', ("//?/c:", "/dir"))
126        tester('ntpath.splitdrive("//?/UNC")', ("//?/UNC", ""))
127        tester('ntpath.splitdrive("//?/UNC/")', ("//?/UNC/", ""))
128        tester('ntpath.splitdrive("//?/UNC/server/")', ("//?/UNC/server/", ""))
129        tester('ntpath.splitdrive("//?/UNC/server/share")', ("//?/UNC/server/share", ""))
130        tester('ntpath.splitdrive("//?/UNC/server/share/dir")', ("//?/UNC/server/share", "/dir"))
131        tester('ntpath.splitdrive("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")',
132               ('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/spam'))
133        tester('ntpath.splitdrive("//?/BootPartition/")', ("//?/BootPartition", "/"))
134
135        tester('ntpath.splitdrive("\\\\?\\c:")', ("\\\\?\\c:", ""))
136        tester('ntpath.splitdrive("\\\\?\\c:\\")', ("\\\\?\\c:", "\\"))
137        tester('ntpath.splitdrive("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\dir"))
138        tester('ntpath.splitdrive("\\\\?\\UNC")', ("\\\\?\\UNC", ""))
139        tester('ntpath.splitdrive("\\\\?\\UNC\\")', ("\\\\?\\UNC\\", ""))
140        tester('ntpath.splitdrive("\\\\?\\UNC\\server\\")', ("\\\\?\\UNC\\server\\", ""))
141        tester('ntpath.splitdrive("\\\\?\\UNC\\server\\share")', ("\\\\?\\UNC\\server\\share", ""))
142        tester('ntpath.splitdrive("\\\\?\\UNC\\server\\share\\dir")',
143               ("\\\\?\\UNC\\server\\share", "\\dir"))
144        tester('ntpath.splitdrive("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")',
145               ('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\spam'))
146        tester('ntpath.splitdrive("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\"))
147
148        # gh-96290: support partial/invalid UNC drives
149        tester('ntpath.splitdrive("//")', ("//", ""))  # empty server & missing share
150        tester('ntpath.splitdrive("///")', ("///", ""))  # empty server & empty share
151        tester('ntpath.splitdrive("///y")', ("///y", ""))  # empty server & non-empty share
152        tester('ntpath.splitdrive("//x")', ("//x", ""))  # non-empty server & missing share
153        tester('ntpath.splitdrive("//x/")', ("//x/", ""))  # non-empty server & empty share
154
155    def test_split(self):
156        tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar'))
157        tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")',
158               ('\\\\conky\\mountpoint\\foo', 'bar'))
159
160        tester('ntpath.split("c:\\")', ('c:\\', ''))
161        tester('ntpath.split("\\\\conky\\mountpoint\\")',
162               ('\\\\conky\\mountpoint\\', ''))
163
164        tester('ntpath.split("c:/")', ('c:/', ''))
165        tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', ''))
166
167    def test_isabs(self):
168        tester('ntpath.isabs("c:\\")', 1)
169        tester('ntpath.isabs("\\\\conky\\mountpoint\\")', 1)
170        tester('ntpath.isabs("\\foo")', 1)
171        tester('ntpath.isabs("\\foo\\bar")', 1)
172
173        # gh-96290: normal UNC paths and device paths without trailing backslashes
174        tester('ntpath.isabs("\\\\conky\\mountpoint")', 1)
175        tester('ntpath.isabs("\\\\.\\C:")', 1)
176
177    def test_commonprefix(self):
178        tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])',
179               "/home/swen")
180        tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])',
181               "\\home\\swen\\")
182        tester('ntpath.commonprefix(["/home/swen/spam", "/home/swen/spam"])',
183               "/home/swen/spam")
184
185    def test_join(self):
186        tester('ntpath.join("")', '')
187        tester('ntpath.join("", "", "")', '')
188        tester('ntpath.join("a")', 'a')
189        tester('ntpath.join("/a")', '/a')
190        tester('ntpath.join("\\a")', '\\a')
191        tester('ntpath.join("a:")', 'a:')
192        tester('ntpath.join("a:", "\\b")', 'a:\\b')
193        tester('ntpath.join("a", "\\b")', '\\b')
194        tester('ntpath.join("a", "b", "c")', 'a\\b\\c')
195        tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c')
196        tester('ntpath.join("a", "b\\", "c")', 'a\\b\\c')
197        tester('ntpath.join("a", "b", "\\c")', '\\c')
198        tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep')
199        tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b')
200
201        tester("ntpath.join('', 'a')", 'a')
202        tester("ntpath.join('', '', '', '', 'a')", 'a')
203        tester("ntpath.join('a', '')", 'a\\')
204        tester("ntpath.join('a', '', '', '', '')", 'a\\')
205        tester("ntpath.join('a\\', '')", 'a\\')
206        tester("ntpath.join('a\\', '', '', '', '')", 'a\\')
207        tester("ntpath.join('a/', '')", 'a/')
208
209        tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y')
210        tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y')
211        tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y')
212        tester("ntpath.join('c:', 'x/y')", 'c:x/y')
213        tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y')
214        tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y')
215        tester("ntpath.join('c:/', 'x/y')", 'c:/x/y')
216        tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y')
217        tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y')
218        tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y')
219        tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y')
220        tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y')
221
222        tester("ntpath.join('a/b', '/x/y')", '/x/y')
223        tester("ntpath.join('/a/b', '/x/y')", '/x/y')
224        tester("ntpath.join('c:', '/x/y')", 'c:/x/y')
225        tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y')
226        tester("ntpath.join('c:/', '/x/y')", 'c:/x/y')
227        tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y')
228        tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y')
229        tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y')
230        tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y')
231
232        tester("ntpath.join('c:', 'C:x/y')", 'C:x/y')
233        tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y')
234        tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y')
235        tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y')
236
237        for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b',
238                  '//computer/share', '//computer/share/', '//computer/share/a/b'):
239            for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y',
240                      '//machine/common', '//machine/common/', '//machine/common/x/y'):
241                tester("ntpath.join(%r, %r)" % (x, y), y)
242
243        tester("ntpath.join('\\\\computer\\share\\', 'a', 'b')", '\\\\computer\\share\\a\\b')
244        tester("ntpath.join('\\\\computer\\share', 'a', 'b')", '\\\\computer\\share\\a\\b')
245        tester("ntpath.join('\\\\computer\\share', 'a\\b')", '\\\\computer\\share\\a\\b')
246        tester("ntpath.join('//computer/share/', 'a', 'b')", '//computer/share/a\\b')
247        tester("ntpath.join('//computer/share', 'a', 'b')", '//computer/share\\a\\b')
248        tester("ntpath.join('//computer/share', 'a/b')", '//computer/share\\a/b')
249
250    def test_normpath(self):
251        tester("ntpath.normpath('A//////././//.//B')", r'A\B')
252        tester("ntpath.normpath('A/./B')", r'A\B')
253        tester("ntpath.normpath('A/foo/../B')", r'A\B')
254        tester("ntpath.normpath('C:A//B')", r'C:A\B')
255        tester("ntpath.normpath('D:A/./B')", r'D:A\B')
256        tester("ntpath.normpath('e:A/foo/../B')", r'e:A\B')
257
258        tester("ntpath.normpath('C:///A//B')", r'C:\A\B')
259        tester("ntpath.normpath('D:///A/./B')", r'D:\A\B')
260        tester("ntpath.normpath('e:///A/foo/../B')", r'e:\A\B')
261
262        tester("ntpath.normpath('..')", r'..')
263        tester("ntpath.normpath('.')", r'.')
264        tester("ntpath.normpath('')", r'.')
265        tester("ntpath.normpath('/')", '\\')
266        tester("ntpath.normpath('c:/')", 'c:\\')
267        tester("ntpath.normpath('/../.././..')", '\\')
268        tester("ntpath.normpath('c:/../../..')", 'c:\\')
269        tester("ntpath.normpath('../.././..')", r'..\..\..')
270        tester("ntpath.normpath('K:../.././..')", r'K:..\..\..')
271        tester("ntpath.normpath('C:////a/b')", r'C:\a\b')
272        tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b')
273
274        tester("ntpath.normpath('\\\\.\\NUL')", r'\\.\NUL')
275        tester("ntpath.normpath('\\\\?\\D:/XY\\Z')", r'\\?\D:/XY\Z')
276        tester("ntpath.normpath('handbook/../../Tests/image.png')", r'..\Tests\image.png')
277        tester("ntpath.normpath('handbook/../../../Tests/image.png')", r'..\..\Tests\image.png')
278        tester("ntpath.normpath('handbook///../a/.././../b/c')", r'..\b\c')
279        tester("ntpath.normpath('handbook/a/../..///../../b/c')", r'..\..\b\c')
280
281        tester("ntpath.normpath('//server/share/..')" ,    '\\\\server\\share\\')
282        tester("ntpath.normpath('//server/share/../')" ,   '\\\\server\\share\\')
283        tester("ntpath.normpath('//server/share/../..')",  '\\\\server\\share\\')
284        tester("ntpath.normpath('//server/share/../../')", '\\\\server\\share\\')
285
286        # gh-96290: don't normalize partial/invalid UNC drives as rooted paths.
287        tester("ntpath.normpath('\\\\foo\\\\')", '\\\\foo\\\\')
288        tester("ntpath.normpath('\\\\foo\\')", '\\\\foo\\')
289        tester("ntpath.normpath('\\\\foo')", '\\\\foo')
290        tester("ntpath.normpath('\\\\')", '\\\\')
291
292    def test_realpath_curdir(self):
293        expected = ntpath.normpath(os.getcwd())
294        tester("ntpath.realpath('.')", expected)
295        tester("ntpath.realpath('./.')", expected)
296        tester("ntpath.realpath('/'.join(['.'] * 100))", expected)
297        tester("ntpath.realpath('.\\.')", expected)
298        tester("ntpath.realpath('\\'.join(['.'] * 100))", expected)
299
300    def test_realpath_pardir(self):
301        expected = ntpath.normpath(os.getcwd())
302        tester("ntpath.realpath('..')", ntpath.dirname(expected))
303        tester("ntpath.realpath('../..')",
304               ntpath.dirname(ntpath.dirname(expected)))
305        tester("ntpath.realpath('/'.join(['..'] * 50))",
306               ntpath.splitdrive(expected)[0] + '\\')
307        tester("ntpath.realpath('..\\..')",
308               ntpath.dirname(ntpath.dirname(expected)))
309        tester("ntpath.realpath('\\'.join(['..'] * 50))",
310               ntpath.splitdrive(expected)[0] + '\\')
311
312    @os_helper.skip_unless_symlink
313    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
314    def test_realpath_basic(self):
315        ABSTFN = ntpath.abspath(os_helper.TESTFN)
316        open(ABSTFN, "wb").close()
317        self.addCleanup(os_helper.unlink, ABSTFN)
318        self.addCleanup(os_helper.unlink, ABSTFN + "1")
319
320        os.symlink(ABSTFN, ABSTFN + "1")
321        self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN)
322        self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1")),
323                         os.fsencode(ABSTFN))
324
325        # gh-88013: call ntpath.realpath with binary drive name may raise a
326        # TypeError. The drive should not exist to reproduce the bug.
327        for c in string.ascii_uppercase:
328            d = f"{c}:\\"
329            if not ntpath.exists(d):
330                break
331        else:
332            raise OSError("No free drive letters available")
333        self.assertEqual(ntpath.realpath(d), d)
334
335    @os_helper.skip_unless_symlink
336    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
337    def test_realpath_strict(self):
338        # Bug #43757: raise FileNotFoundError in strict mode if we encounter
339        # a path that does not exist.
340        ABSTFN = ntpath.abspath(os_helper.TESTFN)
341        os.symlink(ABSTFN + "1", ABSTFN)
342        self.addCleanup(os_helper.unlink, ABSTFN)
343        self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN, strict=True)
344        self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN + "2", strict=True)
345
346    @os_helper.skip_unless_symlink
347    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
348    def test_realpath_relative(self):
349        ABSTFN = ntpath.abspath(os_helper.TESTFN)
350        open(ABSTFN, "wb").close()
351        self.addCleanup(os_helper.unlink, ABSTFN)
352        self.addCleanup(os_helper.unlink, ABSTFN + "1")
353
354        os.symlink(ABSTFN, ntpath.relpath(ABSTFN + "1"))
355        self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN)
356
357    @os_helper.skip_unless_symlink
358    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
359    def test_realpath_broken_symlinks(self):
360        ABSTFN = ntpath.abspath(os_helper.TESTFN)
361        os.mkdir(ABSTFN)
362        self.addCleanup(os_helper.rmtree, ABSTFN)
363
364        with os_helper.change_cwd(ABSTFN):
365            os.mkdir("subdir")
366            os.chdir("subdir")
367            os.symlink(".", "recursive")
368            os.symlink("..", "parent")
369            os.chdir("..")
370            os.symlink(".", "self")
371            os.symlink("missing", "broken")
372            os.symlink(r"broken\bar", "broken1")
373            os.symlink(r"self\self\broken", "broken2")
374            os.symlink(r"subdir\parent\subdir\parent\broken", "broken3")
375            os.symlink(ABSTFN + r"\broken", "broken4")
376            os.symlink(r"recursive\..\broken", "broken5")
377
378            self.assertPathEqual(ntpath.realpath("broken"),
379                                 ABSTFN + r"\missing")
380            self.assertPathEqual(ntpath.realpath(r"broken\foo"),
381                                 ABSTFN + r"\missing\foo")
382            # bpo-38453: We no longer recursively resolve segments of relative
383            # symlinks that the OS cannot resolve.
384            self.assertPathEqual(ntpath.realpath(r"broken1"),
385                                 ABSTFN + r"\broken\bar")
386            self.assertPathEqual(ntpath.realpath(r"broken1\baz"),
387                                 ABSTFN + r"\broken\bar\baz")
388            self.assertPathEqual(ntpath.realpath("broken2"),
389                                 ABSTFN + r"\self\self\missing")
390            self.assertPathEqual(ntpath.realpath("broken3"),
391                                 ABSTFN + r"\subdir\parent\subdir\parent\missing")
392            self.assertPathEqual(ntpath.realpath("broken4"),
393                                 ABSTFN + r"\missing")
394            self.assertPathEqual(ntpath.realpath("broken5"),
395                                 ABSTFN + r"\missing")
396
397            self.assertPathEqual(ntpath.realpath(b"broken"),
398                                 os.fsencode(ABSTFN + r"\missing"))
399            self.assertPathEqual(ntpath.realpath(rb"broken\foo"),
400                                 os.fsencode(ABSTFN + r"\missing\foo"))
401            self.assertPathEqual(ntpath.realpath(rb"broken1"),
402                                 os.fsencode(ABSTFN + r"\broken\bar"))
403            self.assertPathEqual(ntpath.realpath(rb"broken1\baz"),
404                                 os.fsencode(ABSTFN + r"\broken\bar\baz"))
405            self.assertPathEqual(ntpath.realpath(b"broken2"),
406                                 os.fsencode(ABSTFN + r"\self\self\missing"))
407            self.assertPathEqual(ntpath.realpath(rb"broken3"),
408                                 os.fsencode(ABSTFN + r"\subdir\parent\subdir\parent\missing"))
409            self.assertPathEqual(ntpath.realpath(b"broken4"),
410                                 os.fsencode(ABSTFN + r"\missing"))
411            self.assertPathEqual(ntpath.realpath(b"broken5"),
412                                 os.fsencode(ABSTFN + r"\missing"))
413
414    @os_helper.skip_unless_symlink
415    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
416    def test_realpath_symlink_loops(self):
417        # Symlink loops in non-strict mode are non-deterministic as to which
418        # path is returned, but it will always be the fully resolved path of
419        # one member of the cycle
420        ABSTFN = ntpath.abspath(os_helper.TESTFN)
421        self.addCleanup(os_helper.unlink, ABSTFN)
422        self.addCleanup(os_helper.unlink, ABSTFN + "1")
423        self.addCleanup(os_helper.unlink, ABSTFN + "2")
424        self.addCleanup(os_helper.unlink, ABSTFN + "y")
425        self.addCleanup(os_helper.unlink, ABSTFN + "c")
426        self.addCleanup(os_helper.unlink, ABSTFN + "a")
427
428        os.symlink(ABSTFN, ABSTFN)
429        self.assertPathEqual(ntpath.realpath(ABSTFN), ABSTFN)
430
431        os.symlink(ABSTFN + "1", ABSTFN + "2")
432        os.symlink(ABSTFN + "2", ABSTFN + "1")
433        expected = (ABSTFN + "1", ABSTFN + "2")
434        self.assertPathIn(ntpath.realpath(ABSTFN + "1"), expected)
435        self.assertPathIn(ntpath.realpath(ABSTFN + "2"), expected)
436
437        self.assertPathIn(ntpath.realpath(ABSTFN + "1\\x"),
438                          (ntpath.join(r, "x") for r in expected))
439        self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\.."),
440                             ntpath.dirname(ABSTFN))
441        self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x"),
442                             ntpath.dirname(ABSTFN) + "\\x")
443        os.symlink(ABSTFN + "x", ABSTFN + "y")
444        self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\"
445                                             + ntpath.basename(ABSTFN) + "y"),
446                             ABSTFN + "x")
447        self.assertPathIn(ntpath.realpath(ABSTFN + "1\\..\\"
448                                          + ntpath.basename(ABSTFN) + "1"),
449                          expected)
450
451        os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a")
452        self.assertPathEqual(ntpath.realpath(ABSTFN + "a"), ABSTFN + "a")
453
454        os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN))
455                   + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c")
456        self.assertPathEqual(ntpath.realpath(ABSTFN + "c"), ABSTFN + "c")
457
458        # Test using relative path as well.
459        self.assertPathEqual(ntpath.realpath(ntpath.basename(ABSTFN)), ABSTFN)
460
461    @os_helper.skip_unless_symlink
462    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
463    def test_realpath_symlink_loops_strict(self):
464        # Symlink loops raise OSError in strict mode
465        ABSTFN = ntpath.abspath(os_helper.TESTFN)
466        self.addCleanup(os_helper.unlink, ABSTFN)
467        self.addCleanup(os_helper.unlink, ABSTFN + "1")
468        self.addCleanup(os_helper.unlink, ABSTFN + "2")
469        self.addCleanup(os_helper.unlink, ABSTFN + "y")
470        self.addCleanup(os_helper.unlink, ABSTFN + "c")
471        self.addCleanup(os_helper.unlink, ABSTFN + "a")
472
473        os.symlink(ABSTFN, ABSTFN)
474        self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=True)
475
476        os.symlink(ABSTFN + "1", ABSTFN + "2")
477        os.symlink(ABSTFN + "2", ABSTFN + "1")
478        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=True)
479        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=True)
480        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=True)
481        # Windows eliminates '..' components before resolving links, so the
482        # following call is not expected to raise.
483        self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=True),
484                             ntpath.dirname(ABSTFN))
485        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\x", strict=True)
486        os.symlink(ABSTFN + "x", ABSTFN + "y")
487        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\"
488                                             + ntpath.basename(ABSTFN) + "y",
489                                             strict=True)
490        self.assertRaises(OSError, ntpath.realpath,
491                          ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1",
492                          strict=True)
493
494        os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a")
495        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=True)
496
497        os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN))
498                   + "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c")
499        self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=True)
500
501        # Test using relative path as well.
502        self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN),
503                          strict=True)
504
505    @os_helper.skip_unless_symlink
506    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
507    def test_realpath_symlink_prefix(self):
508        ABSTFN = ntpath.abspath(os_helper.TESTFN)
509        self.addCleanup(os_helper.unlink, ABSTFN + "3")
510        self.addCleanup(os_helper.unlink, "\\\\?\\" + ABSTFN + "3.")
511        self.addCleanup(os_helper.unlink, ABSTFN + "3link")
512        self.addCleanup(os_helper.unlink, ABSTFN + "3.link")
513
514        with open(ABSTFN + "3", "wb") as f:
515            f.write(b'0')
516        os.symlink(ABSTFN + "3", ABSTFN + "3link")
517
518        with open("\\\\?\\" + ABSTFN + "3.", "wb") as f:
519            f.write(b'1')
520        os.symlink("\\\\?\\" + ABSTFN + "3.", ABSTFN + "3.link")
521
522        self.assertPathEqual(ntpath.realpath(ABSTFN + "3link"),
523                             ABSTFN + "3")
524        self.assertPathEqual(ntpath.realpath(ABSTFN + "3.link"),
525                             "\\\\?\\" + ABSTFN + "3.")
526
527        # Resolved paths should be usable to open target files
528        with open(ntpath.realpath(ABSTFN + "3link"), "rb") as f:
529            self.assertEqual(f.read(), b'0')
530        with open(ntpath.realpath(ABSTFN + "3.link"), "rb") as f:
531            self.assertEqual(f.read(), b'1')
532
533        # When the prefix is included, it is not stripped
534        self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3link"),
535                             "\\\\?\\" + ABSTFN + "3")
536        self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3.link"),
537                             "\\\\?\\" + ABSTFN + "3.")
538
539    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
540    def test_realpath_nul(self):
541        tester("ntpath.realpath('NUL')", r'\\.\NUL')
542
543    @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
544    @unittest.skipUnless(HAVE_GETSHORTPATHNAME, 'need _getshortpathname')
545    def test_realpath_cwd(self):
546        ABSTFN = ntpath.abspath(os_helper.TESTFN)
547
548        os_helper.unlink(ABSTFN)
549        os_helper.rmtree(ABSTFN)
550        os.mkdir(ABSTFN)
551        self.addCleanup(os_helper.rmtree, ABSTFN)
552
553        test_dir_long = ntpath.join(ABSTFN, "MyVeryLongDirectoryName")
554        os.mkdir(test_dir_long)
555
556        test_dir_short = _getshortpathname(test_dir_long)
557        test_file_long = ntpath.join(test_dir_long, "file.txt")
558        test_file_short = ntpath.join(test_dir_short, "file.txt")
559
560        with open(test_file_long, "wb") as f:
561            f.write(b"content")
562
563        self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short))
564
565        with os_helper.change_cwd(test_dir_long):
566            self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
567        with os_helper.change_cwd(test_dir_long.lower()):
568            self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
569        with os_helper.change_cwd(test_dir_short):
570            self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
571
572    def test_expandvars(self):
573        with os_helper.EnvironmentVarGuard() as env:
574            env.clear()
575            env["foo"] = "bar"
576            env["{foo"] = "baz1"
577            env["{foo}"] = "baz2"
578            tester('ntpath.expandvars("foo")', "foo")
579            tester('ntpath.expandvars("$foo bar")', "bar bar")
580            tester('ntpath.expandvars("${foo}bar")', "barbar")
581            tester('ntpath.expandvars("$[foo]bar")', "$[foo]bar")
582            tester('ntpath.expandvars("$bar bar")', "$bar bar")
583            tester('ntpath.expandvars("$?bar")', "$?bar")
584            tester('ntpath.expandvars("$foo}bar")', "bar}bar")
585            tester('ntpath.expandvars("${foo")', "${foo")
586            tester('ntpath.expandvars("${{foo}}")', "baz1}")
587            tester('ntpath.expandvars("$foo$foo")', "barbar")
588            tester('ntpath.expandvars("$bar$bar")', "$bar$bar")
589            tester('ntpath.expandvars("%foo% bar")', "bar bar")
590            tester('ntpath.expandvars("%foo%bar")', "barbar")
591            tester('ntpath.expandvars("%foo%%foo%")', "barbar")
592            tester('ntpath.expandvars("%%foo%%foo%foo%")', "%foo%foobar")
593            tester('ntpath.expandvars("%?bar%")', "%?bar%")
594            tester('ntpath.expandvars("%foo%%bar")', "bar%bar")
595            tester('ntpath.expandvars("\'%foo%\'%bar")', "\'%foo%\'%bar")
596            tester('ntpath.expandvars("bar\'%foo%")', "bar\'%foo%")
597
598    @unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII')
599    def test_expandvars_nonascii(self):
600        def check(value, expected):
601            tester('ntpath.expandvars(%r)' % value, expected)
602        with os_helper.EnvironmentVarGuard() as env:
603            env.clear()
604            nonascii = os_helper.FS_NONASCII
605            env['spam'] = nonascii
606            env[nonascii] = 'ham' + nonascii
607            check('$spam bar', '%s bar' % nonascii)
608            check('$%s bar' % nonascii, '$%s bar' % nonascii)
609            check('${spam}bar', '%sbar' % nonascii)
610            check('${%s}bar' % nonascii, 'ham%sbar' % nonascii)
611            check('$spam}bar', '%s}bar' % nonascii)
612            check('$%s}bar' % nonascii, '$%s}bar' % nonascii)
613            check('%spam% bar', '%s bar' % nonascii)
614            check('%{}% bar'.format(nonascii), 'ham%s bar' % nonascii)
615            check('%spam%bar', '%sbar' % nonascii)
616            check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii)
617
618    def test_expanduser(self):
619        tester('ntpath.expanduser("test")', 'test')
620
621        with os_helper.EnvironmentVarGuard() as env:
622            env.clear()
623            tester('ntpath.expanduser("~test")', '~test')
624
625            env['HOMEDRIVE'] = 'C:\\'
626            env['HOMEPATH'] = 'Users\\eric'
627            env['USERNAME'] = 'eric'
628            tester('ntpath.expanduser("~test")', 'C:\\Users\\test')
629            tester('ntpath.expanduser("~")', 'C:\\Users\\eric')
630
631            del env['HOMEDRIVE']
632            tester('ntpath.expanduser("~test")', 'Users\\test')
633            tester('ntpath.expanduser("~")', 'Users\\eric')
634
635            env.clear()
636            env['USERPROFILE'] = 'C:\\Users\\eric'
637            env['USERNAME'] = 'eric'
638            tester('ntpath.expanduser("~test")', 'C:\\Users\\test')
639            tester('ntpath.expanduser("~")', 'C:\\Users\\eric')
640            tester('ntpath.expanduser("~test\\foo\\bar")',
641                   'C:\\Users\\test\\foo\\bar')
642            tester('ntpath.expanduser("~test/foo/bar")',
643                   'C:\\Users\\test/foo/bar')
644            tester('ntpath.expanduser("~\\foo\\bar")',
645                   'C:\\Users\\eric\\foo\\bar')
646            tester('ntpath.expanduser("~/foo/bar")',
647                   'C:\\Users\\eric/foo/bar')
648
649            # bpo-36264: ignore `HOME` when set on windows
650            env.clear()
651            env['HOME'] = 'F:\\'
652            env['USERPROFILE'] = 'C:\\Users\\eric'
653            env['USERNAME'] = 'eric'
654            tester('ntpath.expanduser("~test")', 'C:\\Users\\test')
655            tester('ntpath.expanduser("~")', 'C:\\Users\\eric')
656
657            # bpo-39899: don't guess another user's home directory if
658            # `%USERNAME% != basename(%USERPROFILE%)`
659            env.clear()
660            env['USERPROFILE'] = 'C:\\Users\\eric'
661            env['USERNAME'] = 'idle'
662            tester('ntpath.expanduser("~test")', '~test')
663            tester('ntpath.expanduser("~")', 'C:\\Users\\eric')
664
665
666
667    @unittest.skipUnless(nt, "abspath requires 'nt' module")
668    def test_abspath(self):
669        tester('ntpath.abspath("C:\\")', "C:\\")
670        tester('ntpath.abspath("\\\\?\\C:////spam////eggs. . .")', "\\\\?\\C:\\spam\\eggs")
671        tester('ntpath.abspath("\\\\.\\C:////spam////eggs. . .")', "\\\\.\\C:\\spam\\eggs")
672        tester('ntpath.abspath("//spam//eggs. . .")',     "\\\\spam\\eggs")
673        tester('ntpath.abspath("\\\\spam\\\\eggs. . .")', "\\\\spam\\eggs")
674        tester('ntpath.abspath("C:/spam. . .")',  "C:\\spam")
675        tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam")
676        tester('ntpath.abspath("C:/nul")',  "\\\\.\\nul")
677        tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul")
678        tester('ntpath.abspath("//..")',           "\\\\")
679        tester('ntpath.abspath("//../")',          "\\\\..\\")
680        tester('ntpath.abspath("//../..")',        "\\\\..\\")
681        tester('ntpath.abspath("//../../")',       "\\\\..\\..\\")
682        tester('ntpath.abspath("//../../../")',    "\\\\..\\..\\")
683        tester('ntpath.abspath("//../../../..")',  "\\\\..\\..\\")
684        tester('ntpath.abspath("//../../../../")', "\\\\..\\..\\")
685        tester('ntpath.abspath("//server")',           "\\\\server")
686        tester('ntpath.abspath("//server/")',          "\\\\server\\")
687        tester('ntpath.abspath("//server/..")',        "\\\\server\\")
688        tester('ntpath.abspath("//server/../")',       "\\\\server\\..\\")
689        tester('ntpath.abspath("//server/../..")',     "\\\\server\\..\\")
690        tester('ntpath.abspath("//server/../../")',    "\\\\server\\..\\")
691        tester('ntpath.abspath("//server/../../..")',  "\\\\server\\..\\")
692        tester('ntpath.abspath("//server/../../../")', "\\\\server\\..\\")
693        tester('ntpath.abspath("//server/share")',        "\\\\server\\share")
694        tester('ntpath.abspath("//server/share/")',       "\\\\server\\share\\")
695        tester('ntpath.abspath("//server/share/..")',     "\\\\server\\share\\")
696        tester('ntpath.abspath("//server/share/../")',    "\\\\server\\share\\")
697        tester('ntpath.abspath("//server/share/../..")',  "\\\\server\\share\\")
698        tester('ntpath.abspath("//server/share/../../")', "\\\\server\\share\\")
699        tester('ntpath.abspath("C:\\nul. . .")', "\\\\.\\nul")
700        tester('ntpath.abspath("//... . .")',  "\\\\")
701        tester('ntpath.abspath("//.. . . .")', "\\\\")
702        tester('ntpath.abspath("//../... . .")',  "\\\\..\\")
703        tester('ntpath.abspath("//../.. . . .")', "\\\\..\\")
704        with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir: # bpo-31047
705            tester('ntpath.abspath("")', cwd_dir)
706            tester('ntpath.abspath(" ")', cwd_dir + "\\ ")
707            tester('ntpath.abspath("?")', cwd_dir + "\\?")
708            drive, _ = ntpath.splitdrive(cwd_dir)
709            tester('ntpath.abspath("/abc/")', drive + "\\abc")
710
711    def test_relpath(self):
712        tester('ntpath.relpath("a")', 'a')
713        tester('ntpath.relpath(ntpath.abspath("a"))', 'a')
714        tester('ntpath.relpath("a/b")', 'a\\b')
715        tester('ntpath.relpath("../a/b")', '..\\a\\b')
716        with os_helper.temp_cwd(os_helper.TESTFN) as cwd_dir:
717            currentdir = ntpath.basename(cwd_dir)
718            tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a')
719            tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b')
720        tester('ntpath.relpath("a", "b/c")', '..\\..\\a')
721        tester('ntpath.relpath("c:/foo/bar/bat", "c:/x/y")', '..\\..\\foo\\bar\\bat')
722        tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a')
723        tester('ntpath.relpath("a", "a")', '.')
724        tester('ntpath.relpath("/foo/bar/bat", "/x/y/z")', '..\\..\\..\\foo\\bar\\bat')
725        tester('ntpath.relpath("/foo/bar/bat", "/foo/bar")', 'bat')
726        tester('ntpath.relpath("/foo/bar/bat", "/")', 'foo\\bar\\bat')
727        tester('ntpath.relpath("/", "/foo/bar/bat")', '..\\..\\..')
728        tester('ntpath.relpath("/foo/bar/bat", "/x")', '..\\foo\\bar\\bat')
729        tester('ntpath.relpath("/x", "/foo/bar/bat")', '..\\..\\..\\x')
730        tester('ntpath.relpath("/", "/")', '.')
731        tester('ntpath.relpath("/a", "/a")', '.')
732        tester('ntpath.relpath("/a/b", "/a/b")', '.')
733        tester('ntpath.relpath("c:/foo", "C:/FOO")', '.')
734
735    def test_commonpath(self):
736        def check(paths, expected):
737            tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'),
738                   expected)
739        def check_error(exc, paths):
740            self.assertRaises(exc, ntpath.commonpath, paths)
741            self.assertRaises(exc, ntpath.commonpath,
742                              [os.fsencode(p) for p in paths])
743
744        self.assertRaises(ValueError, ntpath.commonpath, [])
745        check_error(ValueError, ['C:\\Program Files', 'Program Files'])
746        check_error(ValueError, ['C:\\Program Files', 'C:Program Files'])
747        check_error(ValueError, ['\\Program Files', 'Program Files'])
748        check_error(ValueError, ['Program Files', 'C:\\Program Files'])
749        check(['C:\\Program Files'], 'C:\\Program Files')
750        check(['C:\\Program Files', 'C:\\Program Files'], 'C:\\Program Files')
751        check(['C:\\Program Files\\', 'C:\\Program Files'],
752              'C:\\Program Files')
753        check(['C:\\Program Files\\', 'C:\\Program Files\\'],
754              'C:\\Program Files')
755        check(['C:\\\\Program Files', 'C:\\Program Files\\\\'],
756              'C:\\Program Files')
757        check(['C:\\.\\Program Files', 'C:\\Program Files\\.'],
758              'C:\\Program Files')
759        check(['C:\\', 'C:\\bin'], 'C:\\')
760        check(['C:\\Program Files', 'C:\\bin'], 'C:\\')
761        check(['C:\\Program Files', 'C:\\Program Files\\Bar'],
762              'C:\\Program Files')
763        check(['C:\\Program Files\\Foo', 'C:\\Program Files\\Bar'],
764              'C:\\Program Files')
765        check(['C:\\Program Files', 'C:\\Projects'], 'C:\\')
766        check(['C:\\Program Files\\', 'C:\\Projects'], 'C:\\')
767
768        check(['C:\\Program Files\\Foo', 'C:/Program Files/Bar'],
769              'C:\\Program Files')
770        check(['C:\\Program Files\\Foo', 'c:/program files/bar'],
771              'C:\\Program Files')
772        check(['c:/program files/bar', 'C:\\Program Files\\Foo'],
773              'c:\\program files')
774
775        check_error(ValueError, ['C:\\Program Files', 'D:\\Program Files'])
776
777        check(['spam'], 'spam')
778        check(['spam', 'spam'], 'spam')
779        check(['spam', 'alot'], '')
780        check(['and\\jam', 'and\\spam'], 'and')
781        check(['and\\\\jam', 'and\\spam\\\\'], 'and')
782        check(['and\\.\\jam', '.\\and\\spam'], 'and')
783        check(['and\\jam', 'and\\spam', 'alot'], '')
784        check(['and\\jam', 'and\\spam', 'and'], 'and')
785        check(['C:and\\jam', 'C:and\\spam'], 'C:and')
786
787        check([''], '')
788        check(['', 'spam\\alot'], '')
789        check_error(ValueError, ['', '\\spam\\alot'])
790
791        self.assertRaises(TypeError, ntpath.commonpath,
792                          [b'C:\\Program Files', 'C:\\Program Files\\Foo'])
793        self.assertRaises(TypeError, ntpath.commonpath,
794                          [b'C:\\Program Files', 'Program Files\\Foo'])
795        self.assertRaises(TypeError, ntpath.commonpath,
796                          [b'Program Files', 'C:\\Program Files\\Foo'])
797        self.assertRaises(TypeError, ntpath.commonpath,
798                          ['C:\\Program Files', b'C:\\Program Files\\Foo'])
799        self.assertRaises(TypeError, ntpath.commonpath,
800                          ['C:\\Program Files', b'Program Files\\Foo'])
801        self.assertRaises(TypeError, ntpath.commonpath,
802                          ['Program Files', b'C:\\Program Files\\Foo'])
803
804    @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.")
805    def test_sameopenfile(self):
806        with TemporaryFile() as tf1, TemporaryFile() as tf2:
807            # Make sure the same file is really the same
808            self.assertTrue(ntpath.sameopenfile(tf1.fileno(), tf1.fileno()))
809            # Make sure different files are really different
810            self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno()))
811            # Make sure invalid values don't cause issues on win32
812            if sys.platform == "win32":
813                with self.assertRaises(OSError):
814                    # Invalid file descriptors shouldn't display assert
815                    # dialogs (#4804)
816                    ntpath.sameopenfile(-1, -1)
817
818    def test_ismount(self):
819        self.assertTrue(ntpath.ismount("c:\\"))
820        self.assertTrue(ntpath.ismount("C:\\"))
821        self.assertTrue(ntpath.ismount("c:/"))
822        self.assertTrue(ntpath.ismount("C:/"))
823        self.assertTrue(ntpath.ismount("\\\\.\\c:\\"))
824        self.assertTrue(ntpath.ismount("\\\\.\\C:\\"))
825
826        self.assertTrue(ntpath.ismount(b"c:\\"))
827        self.assertTrue(ntpath.ismount(b"C:\\"))
828        self.assertTrue(ntpath.ismount(b"c:/"))
829        self.assertTrue(ntpath.ismount(b"C:/"))
830        self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\"))
831        self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\"))
832
833        with os_helper.temp_dir() as d:
834            self.assertFalse(ntpath.ismount(d))
835
836        if sys.platform == "win32":
837            #
838            # Make sure the current folder isn't the root folder
839            # (or any other volume root). The drive-relative
840            # locations below cannot then refer to mount points
841            #
842            test_cwd = os.getenv("SystemRoot")
843            drive, path = ntpath.splitdrive(test_cwd)
844            with os_helper.change_cwd(test_cwd):
845                self.assertFalse(ntpath.ismount(drive.lower()))
846                self.assertFalse(ntpath.ismount(drive.upper()))
847
848            self.assertTrue(ntpath.ismount("\\\\localhost\\c$"))
849            self.assertTrue(ntpath.ismount("\\\\localhost\\c$\\"))
850
851            self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$"))
852            self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$\\"))
853
854    def assertEqualCI(self, s1, s2):
855        """Assert that two strings are equal ignoring case differences."""
856        self.assertEqual(s1.lower(), s2.lower())
857
858    @unittest.skipUnless(nt, "OS helpers require 'nt' module")
859    def test_nt_helpers(self):
860        # Trivial validation that the helpers do not break, and support both
861        # unicode and bytes (UTF-8) paths
862
863        executable = nt._getfinalpathname(sys.executable)
864
865        for path in executable, os.fsencode(executable):
866            volume_path = nt._getvolumepathname(path)
867            path_drive = ntpath.splitdrive(path)[0]
868            volume_path_drive = ntpath.splitdrive(volume_path)[0]
869            self.assertEqualCI(path_drive, volume_path_drive)
870
871        cap, free = nt._getdiskusage(sys.exec_prefix)
872        self.assertGreater(cap, 0)
873        self.assertGreater(free, 0)
874        b_cap, b_free = nt._getdiskusage(sys.exec_prefix.encode())
875        # Free space may change, so only test the capacity is equal
876        self.assertEqual(b_cap, cap)
877        self.assertGreater(b_free, 0)
878
879        for path in [sys.prefix, sys.executable]:
880            final_path = nt._getfinalpathname(path)
881            self.assertIsInstance(final_path, str)
882            self.assertGreater(len(final_path), 0)
883
884            b_final_path = nt._getfinalpathname(path.encode())
885            self.assertIsInstance(b_final_path, bytes)
886            self.assertGreater(len(b_final_path), 0)
887
888class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
889    pathmodule = ntpath
890    attributes = ['relpath']
891
892
893class PathLikeTests(NtpathTestCase):
894
895    path = ntpath
896
897    def setUp(self):
898        self.file_name = os_helper.TESTFN
899        self.file_path = FakePath(os_helper.TESTFN)
900        self.addCleanup(os_helper.unlink, self.file_name)
901        with open(self.file_name, 'xb', 0) as file:
902            file.write(b"test_ntpath.PathLikeTests")
903
904    def _check_function(self, func):
905        self.assertPathEqual(func(self.file_path), func(self.file_name))
906
907    def test_path_normcase(self):
908        self._check_function(self.path.normcase)
909        if sys.platform == 'win32':
910            self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ')
911
912    def test_path_isabs(self):
913        self._check_function(self.path.isabs)
914
915    def test_path_join(self):
916        self.assertEqual(self.path.join('a', FakePath('b'), 'c'),
917                         self.path.join('a', 'b', 'c'))
918
919    def test_path_split(self):
920        self._check_function(self.path.split)
921
922    def test_path_splitext(self):
923        self._check_function(self.path.splitext)
924
925    def test_path_splitdrive(self):
926        self._check_function(self.path.splitdrive)
927
928    def test_path_basename(self):
929        self._check_function(self.path.basename)
930
931    def test_path_dirname(self):
932        self._check_function(self.path.dirname)
933
934    def test_path_islink(self):
935        self._check_function(self.path.islink)
936
937    def test_path_lexists(self):
938        self._check_function(self.path.lexists)
939
940    def test_path_ismount(self):
941        self._check_function(self.path.ismount)
942
943    def test_path_expanduser(self):
944        self._check_function(self.path.expanduser)
945
946    def test_path_expandvars(self):
947        self._check_function(self.path.expandvars)
948
949    def test_path_normpath(self):
950        self._check_function(self.path.normpath)
951
952    def test_path_abspath(self):
953        self._check_function(self.path.abspath)
954
955    def test_path_realpath(self):
956        self._check_function(self.path.realpath)
957
958    def test_path_relpath(self):
959        self._check_function(self.path.relpath)
960
961    def test_path_commonpath(self):
962        common_path = self.path.commonpath([self.file_path, self.file_name])
963        self.assertPathEqual(common_path, self.file_name)
964
965    def test_path_isdir(self):
966        self._check_function(self.path.isdir)
967
968
969if __name__ == "__main__":
970    unittest.main()
971