test_genericpath.py 17.7 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 16 17 18 19

def safe_rmdir(dirname):
    try:
        os.rmdir(dirname)
    except OSError:
        pass


20
class GenericTest:
21 22 23 24 25 26 27 28 29 30
    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))
31 32

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

63 64 65 66 67 68 69 70 71 72 73 74
        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"
        )
75 76 77 78 79 80 81 82 83 84 85 86
        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"
        )
87 88 89 90 91 92 93 94 95 96 97 98

        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])

99
    def test_getsize(self):
100
        f = open(support.TESTFN, "wb")
101
        try:
Guido van Rossum's avatar
Guido van Rossum committed
102
            f.write(b"foo")
103
            f.close()
104
            self.assertEqual(self.pathmodule.getsize(support.TESTFN), 3)
105 106 107
        finally:
            if not f.closed:
                f.close()
108
            support.unlink(support.TESTFN)
109 110

    def test_time(self):
111
        f = open(support.TESTFN, "wb")
112
        try:
Guido van Rossum's avatar
Guido van Rossum committed
113
            f.write(b"foo")
114
            f.close()
115
            f = open(support.TESTFN, "ab")
Guido van Rossum's avatar
Guido van Rossum committed
116
            f.write(b"bar")
117
            f.close()
118
            f = open(support.TESTFN, "rb")
119 120
            d = f.read()
            f.close()
121
            self.assertEqual(d, b"foobar")
122

123
            self.assertLessEqual(
124 125
                self.pathmodule.getctime(support.TESTFN),
                self.pathmodule.getmtime(support.TESTFN)
126 127 128 129
            )
        finally:
            if not f.closed:
                f.close()
130
            support.unlink(support.TESTFN)
131 132

    def test_exists(self):
133
        self.assertIs(self.pathmodule.exists(support.TESTFN), False)
134
        f = open(support.TESTFN, "wb")
135
        try:
Guido van Rossum's avatar
Guido van Rossum committed
136
            f.write(b"foo")
137
            f.close()
138 139 140 141
            self.assertIs(self.pathmodule.exists(support.TESTFN), True)
            if not self.pathmodule == genericpath:
                self.assertIs(self.pathmodule.lexists(support.TESTFN),
                              True)
142 143 144
        finally:
            if not f.close():
                f.close()
145
            support.unlink(support.TESTFN)
146

147 148 149 150 151 152 153 154 155 156
    @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))

157
    def test_isdir(self):
158
        self.assertIs(self.pathmodule.isdir(support.TESTFN), False)
159
        f = open(support.TESTFN, "wb")
160
        try:
Guido van Rossum's avatar
Guido van Rossum committed
161
            f.write(b"foo")
162
            f.close()
163
            self.assertIs(self.pathmodule.isdir(support.TESTFN), False)
164 165
            os.remove(support.TESTFN)
            os.mkdir(support.TESTFN)
166
            self.assertIs(self.pathmodule.isdir(support.TESTFN), True)
167
            os.rmdir(support.TESTFN)
168 169 170
        finally:
            if not f.close():
                f.close()
171 172
            support.unlink(support.TESTFN)
            safe_rmdir(support.TESTFN)
173 174

    def test_isfile(self):
175
        self.assertIs(self.pathmodule.isfile(support.TESTFN), False)
176
        f = open(support.TESTFN, "wb")
177
        try:
Guido van Rossum's avatar
Guido van Rossum committed
178
            f.write(b"foo")
179
            f.close()
180
            self.assertIs(self.pathmodule.isfile(support.TESTFN), True)
181 182
            os.remove(support.TESTFN)
            os.mkdir(support.TESTFN)
183
            self.assertIs(self.pathmodule.isfile(support.TESTFN), False)
184
            os.rmdir(support.TESTFN)
185 186 187
        finally:
            if not f.close():
                f.close()
188 189 190
            support.unlink(support.TESTFN)
            safe_rmdir(support.TESTFN)

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
    @staticmethod
    def _create_file(filename):
        with open(filename, 'wb') as f:
            f.write(b'foo')

    def test_samefile(self):
        try:
            test_fn = support.TESTFN + "1"
            self._create_file(test_fn)
            self.assertTrue(self.pathmodule.samefile(test_fn, test_fn))
            self.assertRaises(TypeError, self.pathmodule.samefile)
        finally:
            os.remove(test_fn)

    @support.skip_unless_symlink
206 207 208 209 210 211 212
    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)

    def _test_samefile_on_link_func(self, func):
213 214 215 216 217
        try:
            test_fn1 = support.TESTFN + "1"
            test_fn2 = support.TESTFN + "2"
            self._create_file(test_fn1)

218
            func(test_fn1, test_fn2)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
            self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
            os.remove(test_fn2)

            self._create_file(test_fn2)
            self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
        finally:
            os.remove(test_fn1)
            os.remove(test_fn2)

    def test_samestat(self):
        try:
            test_fn = support.TESTFN + "1"
            self._create_file(test_fn)
            test_fns = [test_fn]*2
            stats = map(os.stat, test_fns)
            self.assertTrue(self.pathmodule.samestat(*stats))
        finally:
            os.remove(test_fn)

    @support.skip_unless_symlink
239 240 241 242 243 244 245
    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)

    def _test_samestat_on_link_func(self, func):
246 247 248 249 250
        try:
            test_fn1 = support.TESTFN + "1"
            test_fn2 = support.TESTFN + "2"
            self._create_file(test_fn1)
            test_fns = (test_fn1, test_fn2)
251
            func(*test_fns)
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
            stats = map(os.stat, test_fns)
            self.assertTrue(self.pathmodule.samestat(*stats))
            os.remove(test_fn2)

            self._create_file(test_fn2)
            stats = map(os.stat, test_fns)
            self.assertFalse(self.pathmodule.samestat(*stats))

            self.assertRaises(TypeError, self.pathmodule.samestat)
        finally:
            os.remove(test_fn1)
            os.remove(test_fn2)

    def test_sameopenfile(self):
        fname = support.TESTFN + "1"
        with open(fname, "wb") as a, open(fname, "wb") as b:
            self.assertTrue(self.pathmodule.sameopenfile(
                                a.fileno(), b.fileno()))

271 272 273 274 275
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
276 277


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

281 282 283 284 285 286 287 288 289 290 291 292
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):
293 294 295 296 297 298 299 300 301 302 303 304
        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)
305 306 307 308 309 310 311 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

    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")

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    @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))

378 379
    def test_abspath(self):
        self.assertIn("foo", self.pathmodule.abspath("foo"))
380 381 382
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            self.assertIn(b"foo", self.pathmodule.abspath(b"foo"))
383 384

        # Abspath returns bytes when the arg is bytes
385 386 387 388
        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)
389 390 391

    def test_realpath(self):
        self.assertIn("foo", self.pathmodule.realpath("foo"))
392 393 394
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            self.assertIn(b"foo", self.pathmodule.realpath(b"foo"))
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

    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:
410
            os.fsencode(unicwd)
411 412 413 414 415 416 417 418
        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)

419
    def test_nonascii_abspath(self):
420 421 422 423 424 425 426 427 428
        if (support.TESTFN_UNDECODABLE
        # Mac OS X denies the creation of a directory with an invalid
        # UTF-8 name. Windows allows to create a directory with an
        # 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
429
        else:
430
            self.skipTest("need support.TESTFN_NONASCII")
431

432 433
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
434
            with support.temp_cwd(name):
435
                self.test_abspath()
436

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
    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
            errmsg = r'join\(\) argument must be str or bytes, not %r'
            with self.assertRaisesRegex(TypeError, errmsg % 'int'):
                self.pathmodule.join(42, 'str')
            with self.assertRaisesRegex(TypeError, errmsg % 'int'):
                self.pathmodule.join('str', 42)
            with self.assertRaisesRegex(TypeError, errmsg % 'bytearray'):
                self.pathmodule.join(bytearray(b'foo'), bytearray(b'bar'))

    def test_relpath_errors(self):
        # Check relpath() raises friendly TypeErrors.
456 457
        with support.check_warnings(('', (BytesWarning, DeprecationWarning)),
                                    quiet=True):
458 459 460 461 462 463 464 465 466 467 468 469 470
            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')
            errmsg = r'relpath\(\) argument must be str or bytes, not %r'
            with self.assertRaisesRegex(TypeError, errmsg % 'int'):
                self.pathmodule.relpath(42, 'str')
            with self.assertRaisesRegex(TypeError, errmsg % 'int'):
                self.pathmodule.relpath('str', 42)
            with self.assertRaisesRegex(TypeError, errmsg % 'bytearray'):
                self.pathmodule.relpath(bytearray(b'foo'), bytearray(b'bar'))

471 472

if __name__=="__main__":
473
    unittest.main()