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