• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Tests common to genericpath, macpath, ntpath and posixpath
3"""
4
5import genericpath
6import os
7import sys
8import unittest
9import warnings
10from test import support
11android_not_root = support.android_not_root
12
13
14def create_file(filename, data=b'foo'):
15    with open(filename, 'xb', 0) as fp:
16        fp.write(data)
17
18
19class GenericTest:
20    common_attributes = ['commonprefix', 'getsize', 'getatime', 'getctime',
21                         'getmtime', 'exists', 'isdir', 'isfile']
22    attributes = []
23
24    def test_no_argument(self):
25        for attr in self.common_attributes + self.attributes:
26            with self.assertRaises(TypeError):
27                getattr(self.pathmodule, attr)()
28                raise self.fail("{}.{}() did not raise a TypeError"
29                                .format(self.pathmodule.__name__, attr))
30
31    def test_commonprefix(self):
32        commonprefix = self.pathmodule.commonprefix
33        self.assertEqual(
34            commonprefix([]),
35            ""
36        )
37        self.assertEqual(
38            commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
39            "/home/swen"
40        )
41        self.assertEqual(
42            commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
43            "/home/swen/"
44        )
45        self.assertEqual(
46            commonprefix(["/home/swen/spam", "/home/swen/spam"]),
47            "/home/swen/spam"
48        )
49        self.assertEqual(
50            commonprefix(["home:swenson:spam", "home:swen:spam"]),
51            "home:swen"
52        )
53        self.assertEqual(
54            commonprefix([":home:swen:spam", ":home:swen:eggs"]),
55            ":home:swen:"
56        )
57        self.assertEqual(
58            commonprefix([":home:swen:spam", ":home:swen:spam"]),
59            ":home:swen:spam"
60        )
61
62        self.assertEqual(
63            commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]),
64            b"/home/swen"
65        )
66        self.assertEqual(
67            commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]),
68            b"/home/swen/"
69        )
70        self.assertEqual(
71            commonprefix([b"/home/swen/spam", b"/home/swen/spam"]),
72            b"/home/swen/spam"
73        )
74        self.assertEqual(
75            commonprefix([b"home:swenson:spam", b"home:swen:spam"]),
76            b"home:swen"
77        )
78        self.assertEqual(
79            commonprefix([b":home:swen:spam", b":home:swen:eggs"]),
80            b":home:swen:"
81        )
82        self.assertEqual(
83            commonprefix([b":home:swen:spam", b":home:swen:spam"]),
84            b":home:swen:spam"
85        )
86
87        testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd',
88                    'aXc', 'abd', 'ab', 'aX', 'abcX']
89        for s1 in testlist:
90            for s2 in testlist:
91                p = commonprefix([s1, s2])
92                self.assertTrue(s1.startswith(p))
93                self.assertTrue(s2.startswith(p))
94                if s1 != s2:
95                    n = len(p)
96                    self.assertNotEqual(s1[n:n+1], s2[n:n+1])
97
98    def test_getsize(self):
99        filename = support.TESTFN
100        self.addCleanup(support.unlink, filename)
101
102        create_file(filename, b'Hello')
103        self.assertEqual(self.pathmodule.getsize(filename), 5)
104        os.remove(filename)
105
106        create_file(filename, b'Hello World!')
107        self.assertEqual(self.pathmodule.getsize(filename), 12)
108
109    def test_filetime(self):
110        filename = support.TESTFN
111        self.addCleanup(support.unlink, filename)
112
113        create_file(filename, b'foo')
114
115        with open(filename, "ab", 0) as f:
116            f.write(b"bar")
117
118        with open(filename, "rb", 0) as f:
119            data = f.read()
120        self.assertEqual(data, b"foobar")
121
122        self.assertLessEqual(
123            self.pathmodule.getctime(filename),
124            self.pathmodule.getmtime(filename)
125        )
126
127    def test_exists(self):
128        filename = support.TESTFN
129        self.addCleanup(support.unlink, filename)
130
131        self.assertIs(self.pathmodule.exists(filename), False)
132
133        with open(filename, "xb") as f:
134            f.write(b"foo")
135
136        self.assertIs(self.pathmodule.exists(filename), True)
137
138        if not self.pathmodule == genericpath:
139            self.assertIs(self.pathmodule.lexists(filename), True)
140
141    @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
142    def test_exists_fd(self):
143        r, w = os.pipe()
144        try:
145            self.assertTrue(self.pathmodule.exists(r))
146        finally:
147            os.close(r)
148            os.close(w)
149        self.assertFalse(self.pathmodule.exists(r))
150
151    def test_isdir_file(self):
152        filename = support.TESTFN
153        self.addCleanup(support.unlink, filename)
154        self.assertIs(self.pathmodule.isdir(filename), False)
155
156        create_file(filename)
157        self.assertIs(self.pathmodule.isdir(filename), False)
158
159    def test_isdir_dir(self):
160        filename = support.TESTFN
161        self.addCleanup(support.rmdir, filename)
162        self.assertIs(self.pathmodule.isdir(filename), False)
163
164        os.mkdir(filename)
165        self.assertIs(self.pathmodule.isdir(filename), True)
166
167    def test_isfile_file(self):
168        filename = support.TESTFN
169        self.addCleanup(support.unlink, filename)
170        self.assertIs(self.pathmodule.isfile(filename), False)
171
172        create_file(filename)
173        self.assertIs(self.pathmodule.isfile(filename), True)
174
175    def test_isfile_dir(self):
176        filename = support.TESTFN
177        self.addCleanup(support.rmdir, filename)
178        self.assertIs(self.pathmodule.isfile(filename), False)
179
180        os.mkdir(filename)
181        self.assertIs(self.pathmodule.isfile(filename), False)
182
183    def test_samefile(self):
184        file1 = support.TESTFN
185        file2 = support.TESTFN + "2"
186        self.addCleanup(support.unlink, file1)
187        self.addCleanup(support.unlink, file2)
188
189        create_file(file1)
190        self.assertTrue(self.pathmodule.samefile(file1, file1))
191
192        create_file(file2)
193        self.assertFalse(self.pathmodule.samefile(file1, file2))
194
195        self.assertRaises(TypeError, self.pathmodule.samefile)
196
197    def _test_samefile_on_link_func(self, func):
198        test_fn1 = support.TESTFN
199        test_fn2 = support.TESTFN + "2"
200        self.addCleanup(support.unlink, test_fn1)
201        self.addCleanup(support.unlink, test_fn2)
202
203        create_file(test_fn1)
204
205        func(test_fn1, test_fn2)
206        self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
207        os.remove(test_fn2)
208
209        create_file(test_fn2)
210        self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
211
212    @support.skip_unless_symlink
213    def test_samefile_on_symlink(self):
214        self._test_samefile_on_link_func(os.symlink)
215
216    @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
217    def test_samefile_on_link(self):
218        self._test_samefile_on_link_func(os.link)
219
220    def test_samestat(self):
221        test_fn1 = support.TESTFN
222        test_fn2 = support.TESTFN + "2"
223        self.addCleanup(support.unlink, test_fn1)
224        self.addCleanup(support.unlink, test_fn2)
225
226        create_file(test_fn1)
227        stat1 = os.stat(test_fn1)
228        self.assertTrue(self.pathmodule.samestat(stat1, os.stat(test_fn1)))
229
230        create_file(test_fn2)
231        stat2 = os.stat(test_fn2)
232        self.assertFalse(self.pathmodule.samestat(stat1, stat2))
233
234        self.assertRaises(TypeError, self.pathmodule.samestat)
235
236    def _test_samestat_on_link_func(self, func):
237        test_fn1 = support.TESTFN + "1"
238        test_fn2 = support.TESTFN + "2"
239        self.addCleanup(support.unlink, test_fn1)
240        self.addCleanup(support.unlink, test_fn2)
241
242        create_file(test_fn1)
243        func(test_fn1, test_fn2)
244        self.assertTrue(self.pathmodule.samestat(os.stat(test_fn1),
245                                                 os.stat(test_fn2)))
246        os.remove(test_fn2)
247
248        create_file(test_fn2)
249        self.assertFalse(self.pathmodule.samestat(os.stat(test_fn1),
250                                                  os.stat(test_fn2)))
251
252    @support.skip_unless_symlink
253    def test_samestat_on_symlink(self):
254        self._test_samestat_on_link_func(os.symlink)
255
256    @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
257    def test_samestat_on_link(self):
258        self._test_samestat_on_link_func(os.link)
259
260    def test_sameopenfile(self):
261        filename = support.TESTFN
262        self.addCleanup(support.unlink, filename)
263        create_file(filename)
264
265        with open(filename, "rb", 0) as fp1:
266            fd1 = fp1.fileno()
267            with open(filename, "rb", 0) as fp2:
268                fd2 = fp2.fileno()
269                self.assertTrue(self.pathmodule.sameopenfile(fd1, fd2))
270
271
272class TestGenericTest(GenericTest, unittest.TestCase):
273    # Issue 16852: GenericTest can't inherit from unittest.TestCase
274    # for test discovery purposes; CommonTest inherits from GenericTest
275    # and is only meant to be inherited by others.
276    pathmodule = genericpath
277
278    def test_null_bytes(self):
279        for attr in GenericTest.common_attributes:
280            # os.path.commonprefix doesn't raise ValueError
281            if attr == 'commonprefix':
282                continue
283            with self.subTest(attr=attr):
284                with self.assertRaises(ValueError) as cm:
285                    getattr(self.pathmodule, attr)('/tmp\x00abcds')
286                self.assertIn('embedded null', str(cm.exception))
287
288# Following TestCase is not supposed to be run from test_genericpath.
289# It is inherited by other test modules (macpath, ntpath, posixpath).
290
291class CommonTest(GenericTest):
292    common_attributes = GenericTest.common_attributes + [
293        # Properties
294        'curdir', 'pardir', 'extsep', 'sep',
295        'pathsep', 'defpath', 'altsep', 'devnull',
296        # Methods
297        'normcase', 'splitdrive', 'expandvars', 'normpath', 'abspath',
298        'join', 'split', 'splitext', 'isabs', 'basename', 'dirname',
299        'lexists', 'islink', 'ismount', 'expanduser', 'normpath', 'realpath',
300    ]
301
302    def test_normcase(self):
303        normcase = self.pathmodule.normcase
304        # check that normcase() is idempotent
305        for p in ["FoO/./BaR", b"FoO/./BaR"]:
306            p = normcase(p)
307            self.assertEqual(p, normcase(p))
308
309        self.assertEqual(normcase(''), '')
310        self.assertEqual(normcase(b''), b'')
311
312        # check that normcase raises a TypeError for invalid types
313        for path in (None, True, 0, 2.5, [], bytearray(b''), {'o','o'}):
314            self.assertRaises(TypeError, normcase, path)
315
316    def test_splitdrive(self):
317        # splitdrive for non-NT paths
318        splitdrive = self.pathmodule.splitdrive
319        self.assertEqual(splitdrive("/foo/bar"), ("", "/foo/bar"))
320        self.assertEqual(splitdrive("foo:bar"), ("", "foo:bar"))
321        self.assertEqual(splitdrive(":foo:bar"), ("", ":foo:bar"))
322
323        self.assertEqual(splitdrive(b"/foo/bar"), (b"", b"/foo/bar"))
324        self.assertEqual(splitdrive(b"foo:bar"), (b"", b"foo:bar"))
325        self.assertEqual(splitdrive(b":foo:bar"), (b"", b":foo:bar"))
326
327    def test_expandvars(self):
328        if self.pathmodule.__name__ == 'macpath':
329            self.skipTest('macpath.expandvars is a stub')
330        expandvars = self.pathmodule.expandvars
331        with support.EnvironmentVarGuard() as env:
332            env.clear()
333            env["foo"] = "bar"
334            env["{foo"] = "baz1"
335            env["{foo}"] = "baz2"
336            self.assertEqual(expandvars("foo"), "foo")
337            self.assertEqual(expandvars("$foo bar"), "bar bar")
338            self.assertEqual(expandvars("${foo}bar"), "barbar")
339            self.assertEqual(expandvars("$[foo]bar"), "$[foo]bar")
340            self.assertEqual(expandvars("$bar bar"), "$bar bar")
341            self.assertEqual(expandvars("$?bar"), "$?bar")
342            self.assertEqual(expandvars("$foo}bar"), "bar}bar")
343            self.assertEqual(expandvars("${foo"), "${foo")
344            self.assertEqual(expandvars("${{foo}}"), "baz1}")
345            self.assertEqual(expandvars("$foo$foo"), "barbar")
346            self.assertEqual(expandvars("$bar$bar"), "$bar$bar")
347
348            self.assertEqual(expandvars(b"foo"), b"foo")
349            self.assertEqual(expandvars(b"$foo bar"), b"bar bar")
350            self.assertEqual(expandvars(b"${foo}bar"), b"barbar")
351            self.assertEqual(expandvars(b"$[foo]bar"), b"$[foo]bar")
352            self.assertEqual(expandvars(b"$bar bar"), b"$bar bar")
353            self.assertEqual(expandvars(b"$?bar"), b"$?bar")
354            self.assertEqual(expandvars(b"$foo}bar"), b"bar}bar")
355            self.assertEqual(expandvars(b"${foo"), b"${foo")
356            self.assertEqual(expandvars(b"${{foo}}"), b"baz1}")
357            self.assertEqual(expandvars(b"$foo$foo"), b"barbar")
358            self.assertEqual(expandvars(b"$bar$bar"), b"$bar$bar")
359
360    @unittest.skipUnless(support.FS_NONASCII, 'need support.FS_NONASCII')
361    def test_expandvars_nonascii(self):
362        if self.pathmodule.__name__ == 'macpath':
363            self.skipTest('macpath.expandvars is a stub')
364        expandvars = self.pathmodule.expandvars
365        def check(value, expected):
366            self.assertEqual(expandvars(value), expected)
367        with support.EnvironmentVarGuard() as env:
368            env.clear()
369            nonascii = support.FS_NONASCII
370            env['spam'] = nonascii
371            env[nonascii] = 'ham' + nonascii
372            check(nonascii, nonascii)
373            check('$spam bar', '%s bar' % nonascii)
374            check('${spam}bar', '%sbar' % nonascii)
375            check('${%s}bar' % nonascii, 'ham%sbar' % nonascii)
376            check('$bar%s bar' % nonascii, '$bar%s bar' % nonascii)
377            check('$spam}bar', '%s}bar' % nonascii)
378
379            check(os.fsencode(nonascii), os.fsencode(nonascii))
380            check(b'$spam bar', os.fsencode('%s bar' % nonascii))
381            check(b'${spam}bar', os.fsencode('%sbar' % nonascii))
382            check(os.fsencode('${%s}bar' % nonascii),
383                  os.fsencode('ham%sbar' % nonascii))
384            check(os.fsencode('$bar%s bar' % nonascii),
385                  os.fsencode('$bar%s bar' % nonascii))
386            check(b'$spam}bar', os.fsencode('%s}bar' % nonascii))
387
388    def test_abspath(self):
389        self.assertIn("foo", self.pathmodule.abspath("foo"))
390        with warnings.catch_warnings():
391            warnings.simplefilter("ignore", DeprecationWarning)
392            self.assertIn(b"foo", self.pathmodule.abspath(b"foo"))
393
394        # avoid UnicodeDecodeError on Windows
395        undecodable_path = b'' if sys.platform == 'win32' else b'f\xf2\xf2'
396
397        # Abspath returns bytes when the arg is bytes
398        with warnings.catch_warnings():
399            warnings.simplefilter("ignore", DeprecationWarning)
400            for path in (b'', b'foo', undecodable_path, b'/foo', b'C:\\'):
401                self.assertIsInstance(self.pathmodule.abspath(path), bytes)
402
403    def test_realpath(self):
404        self.assertIn("foo", self.pathmodule.realpath("foo"))
405        with warnings.catch_warnings():
406            warnings.simplefilter("ignore", DeprecationWarning)
407            self.assertIn(b"foo", self.pathmodule.realpath(b"foo"))
408
409    def test_normpath_issue5827(self):
410        # Make sure normpath preserves unicode
411        for path in ('', '.', '/', '\\', '///foo/.//bar//'):
412            self.assertIsInstance(self.pathmodule.normpath(path), str)
413
414    def test_abspath_issue3426(self):
415        # Check that abspath returns unicode when the arg is unicode
416        # with both ASCII and non-ASCII cwds.
417        abspath = self.pathmodule.abspath
418        for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'):
419            self.assertIsInstance(abspath(path), str)
420
421        unicwd = '\xe7w\xf0'
422        try:
423            os.fsencode(unicwd)
424        except (AttributeError, UnicodeEncodeError):
425            # FS encoding is probably ASCII
426            pass
427        else:
428            with support.temp_cwd(unicwd):
429                for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'):
430                    self.assertIsInstance(abspath(path), str)
431
432    def test_nonascii_abspath(self):
433        if (support.TESTFN_UNDECODABLE
434        # Mac OS X denies the creation of a directory with an invalid
435        # UTF-8 name. Windows allows creating a directory with an
436        # arbitrary bytes name, but fails to enter this directory
437        # (when the bytes name is used).
438        and sys.platform not in ('win32', 'darwin')):
439            name = support.TESTFN_UNDECODABLE
440        elif support.TESTFN_NONASCII:
441            name = support.TESTFN_NONASCII
442        else:
443            self.skipTest("need support.TESTFN_NONASCII")
444
445        with warnings.catch_warnings():
446            warnings.simplefilter("ignore", DeprecationWarning)
447            with support.temp_cwd(name):
448                self.test_abspath()
449
450    def test_join_errors(self):
451        # Check join() raises friendly TypeErrors.
452        with support.check_warnings(('', BytesWarning), quiet=True):
453            errmsg = "Can't mix strings and bytes in path components"
454            with self.assertRaisesRegex(TypeError, errmsg):
455                self.pathmodule.join(b'bytes', 'str')
456            with self.assertRaisesRegex(TypeError, errmsg):
457                self.pathmodule.join('str', b'bytes')
458            # regression, see #15377
459            with self.assertRaisesRegex(TypeError, 'int'):
460                self.pathmodule.join(42, 'str')
461            with self.assertRaisesRegex(TypeError, 'int'):
462                self.pathmodule.join('str', 42)
463            with self.assertRaisesRegex(TypeError, 'int'):
464                self.pathmodule.join(42)
465            with self.assertRaisesRegex(TypeError, 'list'):
466                self.pathmodule.join([])
467            with self.assertRaisesRegex(TypeError, 'bytearray'):
468                self.pathmodule.join(bytearray(b'foo'), bytearray(b'bar'))
469
470    def test_relpath_errors(self):
471        # Check relpath() raises friendly TypeErrors.
472        with support.check_warnings(('', (BytesWarning, DeprecationWarning)),
473                                    quiet=True):
474            errmsg = "Can't mix strings and bytes in path components"
475            with self.assertRaisesRegex(TypeError, errmsg):
476                self.pathmodule.relpath(b'bytes', 'str')
477            with self.assertRaisesRegex(TypeError, errmsg):
478                self.pathmodule.relpath('str', b'bytes')
479            with self.assertRaisesRegex(TypeError, 'int'):
480                self.pathmodule.relpath(42, 'str')
481            with self.assertRaisesRegex(TypeError, 'int'):
482                self.pathmodule.relpath('str', 42)
483            with self.assertRaisesRegex(TypeError, 'bytearray'):
484                self.pathmodule.relpath(bytearray(b'foo'), bytearray(b'bar'))
485
486
487class PathLikeTests(unittest.TestCase):
488
489    class PathLike:
490        def __init__(self, path=''):
491            self.path = path
492        def __fspath__(self):
493            if isinstance(self.path, BaseException):
494                raise self.path
495            else:
496                return self.path
497
498    def setUp(self):
499        self.file_name = support.TESTFN.lower()
500        self.file_path = self.PathLike(support.TESTFN)
501        self.addCleanup(support.unlink, self.file_name)
502        create_file(self.file_name, b"test_genericpath.PathLikeTests")
503
504    def assertPathEqual(self, func):
505        self.assertEqual(func(self.file_path), func(self.file_name))
506
507    def test_path_exists(self):
508        self.assertPathEqual(os.path.exists)
509
510    def test_path_isfile(self):
511        self.assertPathEqual(os.path.isfile)
512
513    def test_path_isdir(self):
514        self.assertPathEqual(os.path.isdir)
515
516    def test_path_commonprefix(self):
517        self.assertEqual(os.path.commonprefix([self.file_path, self.file_name]),
518                         self.file_name)
519
520    def test_path_getsize(self):
521        self.assertPathEqual(os.path.getsize)
522
523    def test_path_getmtime(self):
524        self.assertPathEqual(os.path.getatime)
525
526    def test_path_getctime(self):
527        self.assertPathEqual(os.path.getctime)
528
529    def test_path_samefile(self):
530        self.assertTrue(os.path.samefile(self.file_path, self.file_name))
531
532
533if __name__=="__main__":
534    unittest.main()
535