test_genericpath.py 19.4 KB
Newer Older
1 2 3 4
"""
Tests common to genericpath, macpath, ntpath and posixpath
"""

5
import genericpath
6
import os
7
import sys
8 9 10
import unittest
import warnings
from test import support
11

12

13 14 15
def create_file(filename, data=b'foo'):
    with open(filename, 'xb', 0) as fp:
        fp.write(data)
16 17


18
class GenericTest:
19 20 21 22 23 24 25 26 27 28
    common_attributes = ['commonprefix', 'getsize', 'getatime', 'getctime',
                         'getmtime', 'exists', 'isdir', 'isfile']
    attributes = []

    def test_no_argument(self):
        for attr in self.common_attributes + self.attributes:
            with self.assertRaises(TypeError):
                getattr(self.pathmodule, attr)()
                raise self.fail("{}.{}() did not raise a TypeError"
                                .format(self.pathmodule.__name__, attr))
29 30

    def test_commonprefix(self):
31
        commonprefix = self.pathmodule.commonprefix
32
        self.assertEqual(
33
            commonprefix([]),
34 35 36
            ""
        )
        self.assertEqual(
37
            commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
38 39 40
            "/home/swen"
        )
        self.assertEqual(
41
            commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
42 43 44
            "/home/swen/"
        )
        self.assertEqual(
45
            commonprefix(["/home/swen/spam", "/home/swen/spam"]),
46 47
            "/home/swen/spam"
        )
48 49 50 51 52 53 54 55 56 57 58 59
        self.assertEqual(
            commonprefix(["home:swenson:spam", "home:swen:spam"]),
            "home:swen"
        )
        self.assertEqual(
            commonprefix([":home:swen:spam", ":home:swen:eggs"]),
            ":home:swen:"
        )
        self.assertEqual(
            commonprefix([":home:swen:spam", ":home:swen:spam"]),
            ":home:swen:spam"
        )
60

61 62 63 64 65 66 67 68 69 70 71 72
        self.assertEqual(
            commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]),
            b"/home/swen"
        )
        self.assertEqual(
            commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]),
            b"/home/swen/"
        )
        self.assertEqual(
            commonprefix([b"/home/swen/spam", b"/home/swen/spam"]),
            b"/home/swen/spam"
        )
73 74 75 76 77 78 79 80 81 82 83 84
        self.assertEqual(
            commonprefix([b"home:swenson:spam", b"home:swen:spam"]),
            b"home:swen"
        )
        self.assertEqual(
            commonprefix([b":home:swen:spam", b":home:swen:eggs"]),
            b":home:swen:"
        )
        self.assertEqual(
            commonprefix([b":home:swen:spam", b":home:swen:spam"]),
            b":home:swen:spam"
        )
85 86 87 88 89 90 91 92 93 94 95 96

        testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd',
                    'aXc', 'abd', 'ab', 'aX', 'abcX']
        for s1 in testlist:
            for s2 in testlist:
                p = commonprefix([s1, s2])
                self.assertTrue(s1.startswith(p))
                self.assertTrue(s2.startswith(p))
                if s1 != s2:
                    n = len(p)
                    self.assertNotEqual(s1[n:n+1], s2[n:n+1])

97
    def test_getsize(self):
98 99
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)
100

101 102 103 104 105 106 107 108 109 110 111 112 113 114
        create_file(filename, b'Hello')
        self.assertEqual(self.pathmodule.getsize(filename), 5)
        os.remove(filename)

        create_file(filename, b'Hello World!')
        self.assertEqual(self.pathmodule.getsize(filename), 12)

    def test_filetime(self):
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)

        create_file(filename, b'foo')

        with open(filename, "ab", 0) as f:
Guido van Rossum's avatar
Guido van Rossum committed
115
            f.write(b"bar")
116 117 118 119 120 121 122 123 124

        with open(filename, "rb", 0) as f:
            data = f.read()
        self.assertEqual(data, b"foobar")

        self.assertLessEqual(
            self.pathmodule.getctime(filename),
            self.pathmodule.getmtime(filename)
        )
125 126

    def test_exists(self):
127 128 129 130 131 132
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)

        self.assertIs(self.pathmodule.exists(filename), False)

        with open(filename, "xb") as f:
Guido van Rossum's avatar
Guido van Rossum committed
133
            f.write(b"foo")
134 135 136 137 138

        self.assertIs(self.pathmodule.exists(filename), True)

        if not self.pathmodule == genericpath:
            self.assertIs(self.pathmodule.lexists(filename), True)
139

140 141 142 143 144 145 146 147 148 149
    @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
    def test_exists_fd(self):
        r, w = os.pipe()
        try:
            self.assertTrue(self.pathmodule.exists(r))
        finally:
            os.close(r)
            os.close(w)
        self.assertFalse(self.pathmodule.exists(r))

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    def test_isdir_file(self):
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)
        self.assertIs(self.pathmodule.isdir(filename), False)

        create_file(filename)
        self.assertIs(self.pathmodule.isdir(filename), False)

    def test_isdir_dir(self):
        filename = support.TESTFN
        self.addCleanup(support.rmdir, filename)
        self.assertIs(self.pathmodule.isdir(filename), False)

        os.mkdir(filename)
        self.assertIs(self.pathmodule.isdir(filename), True)

    def test_isfile_file(self):
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)
        self.assertIs(self.pathmodule.isfile(filename), False)
170

171 172 173 174 175 176 177 178 179 180
        create_file(filename)
        self.assertIs(self.pathmodule.isfile(filename), True)

    def test_isfile_dir(self):
        filename = support.TESTFN
        self.addCleanup(support.rmdir, filename)
        self.assertIs(self.pathmodule.isfile(filename), False)

        os.mkdir(filename)
        self.assertIs(self.pathmodule.isfile(filename), False)
181 182

    def test_samefile(self):
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
        file1 = support.TESTFN
        file2 = support.TESTFN + "2"
        self.addCleanup(support.unlink, file1)
        self.addCleanup(support.unlink, file2)

        create_file(file1)
        self.assertTrue(self.pathmodule.samefile(file1, file1))

        create_file(file2)
        self.assertFalse(self.pathmodule.samefile(file1, file2))

        self.assertRaises(TypeError, self.pathmodule.samefile)

    def _test_samefile_on_link_func(self, func):
        test_fn1 = support.TESTFN
        test_fn2 = support.TESTFN + "2"
        self.addCleanup(support.unlink, test_fn1)
        self.addCleanup(support.unlink, test_fn2)

        create_file(test_fn1)

        func(test_fn1, test_fn2)
        self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
        os.remove(test_fn2)

        create_file(test_fn2)
        self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
210 211

    @support.skip_unless_symlink
212 213 214 215 216 217
    def test_samefile_on_symlink(self):
        self._test_samefile_on_link_func(os.symlink)

    def test_samefile_on_link(self):
        self._test_samefile_on_link_func(os.link)

218 219 220 221 222
    def test_samestat(self):
        test_fn1 = support.TESTFN
        test_fn2 = support.TESTFN + "2"
        self.addCleanup(support.unlink, test_fn1)
        self.addCleanup(support.unlink, test_fn2)
223

224 225 226
        create_file(test_fn1)
        stat1 = os.stat(test_fn1)
        self.assertTrue(self.pathmodule.samestat(stat1, os.stat(test_fn1)))
227

228 229 230
        create_file(test_fn2)
        stat2 = os.stat(test_fn2)
        self.assertFalse(self.pathmodule.samestat(stat1, stat2))
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        self.assertRaises(TypeError, self.pathmodule.samestat)

    def _test_samestat_on_link_func(self, func):
        test_fn1 = support.TESTFN + "1"
        test_fn2 = support.TESTFN + "2"
        self.addCleanup(support.unlink, test_fn1)
        self.addCleanup(support.unlink, test_fn2)

        create_file(test_fn1)
        func(test_fn1, test_fn2)
        self.assertTrue(self.pathmodule.samestat(os.stat(test_fn1),
                                                 os.stat(test_fn2)))
        os.remove(test_fn2)

        create_file(test_fn2)
        self.assertFalse(self.pathmodule.samestat(os.stat(test_fn1),
                                                  os.stat(test_fn2)))
249 250

    @support.skip_unless_symlink
251 252 253 254 255 256
    def test_samestat_on_symlink(self):
        self._test_samestat_on_link_func(os.symlink)

    def test_samestat_on_link(self):
        self._test_samestat_on_link_func(os.link)

257
    def test_sameopenfile(self):
258 259 260 261 262 263 264 265 266 267
        filename = support.TESTFN
        self.addCleanup(support.unlink, filename)
        create_file(filename)

        with open(filename, "rb", 0) as fp1:
            fd1 = fp1.fileno()
            with open(filename, "rb", 0) as fp2:
                fd2 = fp2.fileno()
                self.assertTrue(self.pathmodule.sameopenfile(fd1, fd2))

268

269 270 271 272 273
class TestGenericTest(GenericTest, unittest.TestCase):
    # Issue 16852: GenericTest can't inherit from unittest.TestCase
    # for test discovery purposes; CommonTest inherits from GenericTest
    # and is only meant to be inherited by others.
    pathmodule = genericpath
274

275 276 277 278 279 280 281 282
    def test_null_bytes(self):
        for attr in GenericTest.common_attributes:
            # os.path.commonprefix doesn't raise ValueError
            if attr == 'commonprefix':
                continue
            with self.subTest(attr=attr):
                with self.assertRaises(ValueError) as cm:
                    getattr(self.pathmodule, attr)('/tmp\x00abcds')
283
                self.assertIn('embedded null', str(cm.exception))
284

285 286 287
# Following TestCase is not supposed to be run from test_genericpath.
# It is inherited by other test modules (macpath, ntpath, posixpath).

288 289 290 291 292 293 294 295 296 297 298 299
class CommonTest(GenericTest):
    common_attributes = GenericTest.common_attributes + [
        # Properties
        'curdir', 'pardir', 'extsep', 'sep',
        'pathsep', 'defpath', 'altsep', 'devnull',
        # Methods
        'normcase', 'splitdrive', 'expandvars', 'normpath', 'abspath',
        'join', 'split', 'splitext', 'isabs', 'basename', 'dirname',
        'lexists', 'islink', 'ismount', 'expanduser', 'normpath', 'realpath',
    ]

    def test_normcase(self):
300 301 302 303 304 305 306 307 308 309 310 311
        normcase = self.pathmodule.normcase
        # check that normcase() is idempotent
        for p in ["FoO/./BaR", b"FoO/./BaR"]:
            p = normcase(p)
            self.assertEqual(p, normcase(p))

        self.assertEqual(normcase(''), '')
        self.assertEqual(normcase(b''), b'')

        # check that normcase raises a TypeError for invalid types
        for path in (None, True, 0, 2.5, [], bytearray(b''), {'o','o'}):
            self.assertRaises(TypeError, normcase, path)
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356

    def test_splitdrive(self):
        # splitdrive for non-NT paths
        splitdrive = self.pathmodule.splitdrive
        self.assertEqual(splitdrive("/foo/bar"), ("", "/foo/bar"))
        self.assertEqual(splitdrive("foo:bar"), ("", "foo:bar"))
        self.assertEqual(splitdrive(":foo:bar"), ("", ":foo:bar"))

        self.assertEqual(splitdrive(b"/foo/bar"), (b"", b"/foo/bar"))
        self.assertEqual(splitdrive(b"foo:bar"), (b"", b"foo:bar"))
        self.assertEqual(splitdrive(b":foo:bar"), (b"", b":foo:bar"))

    def test_expandvars(self):
        if self.pathmodule.__name__ == 'macpath':
            self.skipTest('macpath.expandvars is a stub')
        expandvars = self.pathmodule.expandvars
        with support.EnvironmentVarGuard() as env:
            env.clear()
            env["foo"] = "bar"
            env["{foo"] = "baz1"
            env["{foo}"] = "baz2"
            self.assertEqual(expandvars("foo"), "foo")
            self.assertEqual(expandvars("$foo bar"), "bar bar")
            self.assertEqual(expandvars("${foo}bar"), "barbar")
            self.assertEqual(expandvars("$[foo]bar"), "$[foo]bar")
            self.assertEqual(expandvars("$bar bar"), "$bar bar")
            self.assertEqual(expandvars("$?bar"), "$?bar")
            self.assertEqual(expandvars("$foo}bar"), "bar}bar")
            self.assertEqual(expandvars("${foo"), "${foo")
            self.assertEqual(expandvars("${{foo}}"), "baz1}")
            self.assertEqual(expandvars("$foo$foo"), "barbar")
            self.assertEqual(expandvars("$bar$bar"), "$bar$bar")

            self.assertEqual(expandvars(b"foo"), b"foo")
            self.assertEqual(expandvars(b"$foo bar"), b"bar bar")
            self.assertEqual(expandvars(b"${foo}bar"), b"barbar")
            self.assertEqual(expandvars(b"$[foo]bar"), b"$[foo]bar")
            self.assertEqual(expandvars(b"$bar bar"), b"$bar bar")
            self.assertEqual(expandvars(b"$?bar"), b"$?bar")
            self.assertEqual(expandvars(b"$foo}bar"), b"bar}bar")
            self.assertEqual(expandvars(b"${foo"), b"${foo")
            self.assertEqual(expandvars(b"${{foo}}"), b"baz1}")
            self.assertEqual(expandvars(b"$foo$foo"), b"barbar")
            self.assertEqual(expandvars(b"$bar$bar"), b"$bar$bar")

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
    @unittest.skipUnless(support.FS_NONASCII, 'need support.FS_NONASCII')
    def test_expandvars_nonascii(self):
        if self.pathmodule.__name__ == 'macpath':
            self.skipTest('macpath.expandvars is a stub')
        expandvars = self.pathmodule.expandvars
        def check(value, expected):
            self.assertEqual(expandvars(value), expected)
        with support.EnvironmentVarGuard() as env:
            env.clear()
            nonascii = support.FS_NONASCII
            env['spam'] = nonascii
            env[nonascii] = 'ham' + nonascii
            check(nonascii, nonascii)
            check('$spam bar', '%s bar' % nonascii)
            check('${spam}bar', '%sbar' % nonascii)
            check('${%s}bar' % nonascii, 'ham%sbar' % nonascii)
            check('$bar%s bar' % nonascii, '$bar%s bar' % nonascii)
            check('$spam}bar', '%s}bar' % nonascii)

            check(os.fsencode(nonascii), os.fsencode(nonascii))
            check(b'$spam bar', os.fsencode('%s bar' % nonascii))
            check(b'${spam}bar', os.fsencode('%sbar' % nonascii))
            check(os.fsencode('${%s}bar' % nonascii),
                  os.fsencode('ham%sbar' % nonascii))
            check(os.fsencode('$bar%s bar' % nonascii),
                  os.fsencode('$bar%s bar' % nonascii))
            check(b'$spam}bar', os.fsencode('%s}bar' % nonascii))

385 386
    def test_abspath(self):
        self.assertIn("foo", self.pathmodule.abspath("foo"))
387 388 389
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            self.assertIn(b"foo", self.pathmodule.abspath(b"foo"))
390 391

        # Abspath returns bytes when the arg is bytes
392 393 394 395
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            for path in (b'', b'foo', b'f\xf2\xf2', b'/foo', b'C:\\'):
                self.assertIsInstance(self.pathmodule.abspath(path), bytes)
396 397 398

    def test_realpath(self):
        self.assertIn("foo", self.pathmodule.realpath("foo"))
399 400 401
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            self.assertIn(b"foo", self.pathmodule.realpath(b"foo"))
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

    def test_normpath_issue5827(self):
        # Make sure normpath preserves unicode
        for path in ('', '.', '/', '\\', '///foo/.//bar//'):
            self.assertIsInstance(self.pathmodule.normpath(path), str)

    def test_abspath_issue3426(self):
        # Check that abspath returns unicode when the arg is unicode
        # with both ASCII and non-ASCII cwds.
        abspath = self.pathmodule.abspath
        for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'):
            self.assertIsInstance(abspath(path), str)

        unicwd = '\xe7w\xf0'
        try:
417
            os.fsencode(unicwd)
418 419 420 421 422 423 424 425
        except (AttributeError, UnicodeEncodeError):
            # FS encoding is probably ASCII
            pass
        else:
            with support.temp_cwd(unicwd):
                for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'):
                    self.assertIsInstance(abspath(path), str)

426
    def test_nonascii_abspath(self):
427 428
        if (support.TESTFN_UNDECODABLE
        # Mac OS X denies the creation of a directory with an invalid
429
        # UTF-8 name. Windows allows creating a directory with an
430 431 432 433 434 435
        # arbitrary bytes name, but fails to enter this directory
        # (when the bytes name is used).
        and sys.platform not in ('win32', 'darwin')):
            name = support.TESTFN_UNDECODABLE
        elif support.TESTFN_NONASCII:
            name = support.TESTFN_NONASCII
436
        else:
437
            self.skipTest("need support.TESTFN_NONASCII")
438

439 440
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
441
            with support.temp_cwd(name):
442
                self.test_abspath()
443

444 445 446 447 448 449 450 451 452
    def test_join_errors(self):
        # Check join() raises friendly TypeErrors.
        with support.check_warnings(('', BytesWarning), quiet=True):
            errmsg = "Can't mix strings and bytes in path components"
            with self.assertRaisesRegex(TypeError, errmsg):
                self.pathmodule.join(b'bytes', 'str')
            with self.assertRaisesRegex(TypeError, errmsg):
                self.pathmodule.join('str', b'bytes')
            # regression, see #15377
453
            with self.assertRaisesRegex(TypeError, 'int'):
454
                self.pathmodule.join(42, 'str')
455
            with self.assertRaisesRegex(TypeError, 'int'):
456
                self.pathmodule.join('str', 42)
457
            with self.assertRaisesRegex(TypeError, 'int'):
458
                self.pathmodule.join(42)
459
            with self.assertRaisesRegex(TypeError, 'list'):
460
                self.pathmodule.join([])
461
            with self.assertRaisesRegex(TypeError, 'bytearray'):
462 463 464 465
                self.pathmodule.join(bytearray(b'foo'), bytearray(b'bar'))

    def test_relpath_errors(self):
        # Check relpath() raises friendly TypeErrors.
466 467
        with support.check_warnings(('', (BytesWarning, DeprecationWarning)),
                                    quiet=True):
468 469 470 471 472
            errmsg = "Can't mix strings and bytes in path components"
            with self.assertRaisesRegex(TypeError, errmsg):
                self.pathmodule.relpath(b'bytes', 'str')
            with self.assertRaisesRegex(TypeError, errmsg):
                self.pathmodule.relpath('str', b'bytes')
473
            with self.assertRaisesRegex(TypeError, 'int'):
474
                self.pathmodule.relpath(42, 'str')
475
            with self.assertRaisesRegex(TypeError, 'int'):
476
                self.pathmodule.relpath('str', 42)
477
            with self.assertRaisesRegex(TypeError, 'bytearray'):
478 479
                self.pathmodule.relpath(bytearray(b'foo'), bytearray(b'bar'))

480

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
class PathLikeTests(unittest.TestCase):

    class PathLike:
        def __init__(self, path=''):
            self.path = path
        def __fspath__(self):
            if isinstance(self.path, BaseException):
                raise self.path
            else:
                return self.path

    def setUp(self):
        self.file_name = support.TESTFN.lower()
        self.file_path = self.PathLike(support.TESTFN)
        self.addCleanup(support.unlink, self.file_name)
        create_file(self.file_name, b"test_genericpath.PathLikeTests")

    def assertPathEqual(self, func):
        self.assertEqual(func(self.file_path), func(self.file_name))

    def test_path_exists(self):
        self.assertPathEqual(os.path.exists)

    def test_path_isfile(self):
        self.assertPathEqual(os.path.isfile)

    def test_path_isdir(self):
        self.assertPathEqual(os.path.isdir)

    def test_path_commonprefix(self):
        self.assertEqual(os.path.commonprefix([self.file_path, self.file_name]),
                         self.file_name)

    def test_path_getsize(self):
        self.assertPathEqual(os.path.getsize)

    def test_path_getmtime(self):
        self.assertPathEqual(os.path.getatime)

    def test_path_getctime(self):
        self.assertPathEqual(os.path.getctime)

    def test_path_samefile(self):
        self.assertTrue(os.path.samefile(self.file_path, self.file_name))


527
if __name__=="__main__":
528
    unittest.main()