1# Copyright 2009 Google Inc. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Test that FakeFilesystem calls work identically to a real filesystem.""" 16# pylint: disable-all 17 18import os 19import shutil 20import sys 21import tempfile 22import time 23import unittest 24 25from pyfakefs import fake_filesystem, fake_os, fake_open 26from pyfakefs.helpers import IS_PYPY 27 28 29def sep(path): 30 """Converts slashes in the path to the architecture's path separator.""" 31 if isinstance(path, str): 32 return path.replace("/", os.sep) 33 return path 34 35 36def _get_errno(raised_error): 37 if raised_error is not None: 38 try: 39 return raised_error.errno 40 except AttributeError: 41 pass 42 43 44class TestCase(unittest.TestCase): 45 is_windows = sys.platform.startswith("win") 46 _FAKE_FS_BASE = "C:\\fakefs" if is_windows else "/fakefs" 47 48 49class FakeFilesystemVsRealTest(TestCase): 50 def _paths(self, path): 51 """For a given path, return paths in the real and fake filesystems.""" 52 if not path: 53 return None, None 54 return ( 55 os.path.join(self.real_base, path), 56 os.path.join(self.fake_base, path), 57 ) 58 59 def _create_test_file(self, file_type, path, contents=None): 60 """Create a dir, file, or link in both the real fs and the fake.""" 61 path = sep(path) 62 self._created_files.append([file_type, path, contents]) 63 real_path, fake_path = self._paths(path) 64 if file_type == "d": 65 os.mkdir(real_path) 66 self.fake_os.mkdir(fake_path) 67 if file_type == "f": 68 fh = open(real_path, "w") 69 fh.write(contents or "") 70 fh.close() 71 fh = self.fake_open(fake_path, "w") 72 fh.write(contents or "") 73 fh.close() 74 # b for binary file 75 if file_type == "b": 76 fh = open(real_path, "wb") 77 fh.write(contents or "") 78 fh.close() 79 fh = self.fake_open(fake_path, "wb") 80 fh.write(contents or "") 81 fh.close() 82 # l for symlink, h for hard link 83 if file_type in ("l", "h"): 84 real_target, fake_target = (contents, contents) 85 # If it begins with '/', make it relative to the base. You can't go 86 # creating files in / for the real file system. 87 if contents.startswith(os.sep): 88 real_target, fake_target = self._paths(contents[1:]) 89 if file_type == "l": 90 os.symlink(real_target, real_path) 91 self.fake_os.symlink(fake_target, fake_path) 92 elif file_type == "h": 93 os.link(real_target, real_path) 94 self.fake_os.link(fake_target, fake_path) 95 96 def setUp(self): 97 # Base paths in the real and test file systems. We keep them different 98 # so that missing features in the fake don't fall through to the base 99 # operations and magically succeed. 100 tsname = "fakefs.%s" % time.time() 101 self.cwd = os.getcwd() 102 # Fully expand the base_path - required on OS X. 103 self.real_base = os.path.realpath(os.path.join(tempfile.gettempdir(), tsname)) 104 os.chdir(tempfile.gettempdir()) 105 if os.path.isdir(self.real_base): 106 shutil.rmtree(self.real_base) 107 os.mkdir(self.real_base) 108 self.fake_base = self._FAKE_FS_BASE 109 110 # Make sure we can write to the physical testing temp directory. 111 self.assertTrue(os.access(self.real_base, os.W_OK)) 112 113 self.fake_filesystem = fake_filesystem.FakeFilesystem() 114 self.fake_filesystem.create_dir(self.fake_base) 115 self.fake_os = fake_os.FakeOsModule(self.fake_filesystem) 116 self.fake_open = fake_open.FakeFileOpen(self.fake_filesystem) 117 self._created_files = [] 118 119 os.chdir(self.real_base) 120 self.fake_os.chdir(self.fake_base) 121 122 def tearDown(self): 123 # We have to remove all the files from the real FS. Doing the same for 124 # the fake FS is optional, but doing it is an extra sanity check. 125 os.chdir(tempfile.gettempdir()) 126 try: 127 rev_files = self._created_files[:] 128 rev_files.reverse() 129 for info in rev_files: 130 real_path, fake_path = self._paths(info[1]) 131 if info[0] == "d": 132 try: 133 os.rmdir(real_path) 134 except OSError as e: 135 if "Directory not empty" in e: 136 self.fail( 137 "Real path %s not empty: %s : %s" 138 % (real_path, e, os.listdir(real_path)) 139 ) 140 else: 141 raise 142 self.fake_os.rmdir(fake_path) 143 if info[0] == "f" or info[0] == "l": 144 os.remove(real_path) 145 self.fake_os.remove(fake_path) 146 finally: 147 shutil.rmtree(self.real_base) 148 os.chdir(self.cwd) 149 150 def _compare_behaviors( 151 self, method_name, path, real, fake, method_returns_path=False 152 ): 153 """Invoke an os method in both real and fake contexts and compare 154 results. 155 156 Invoke a real filesystem method with a path to a real file and invoke 157 a fake filesystem method with a path to a fake file and compare the 158 results. We expect some calls to throw Exceptions, so we catch those 159 and compare them. 160 161 Args: 162 method_name: Name of method being tested, for use in 163 error messages. 164 path: potential path to a file in the real and fake file systems, 165 passing an empty tuple indicates that no arguments to pass 166 to method. 167 real: built-in system library or method from the built-in system 168 library which takes a path as an arg and returns some value. 169 fake: fake_filsystem object or method from a fake_filesystem class 170 which takes a path as an arg and returns some value. 171 method_returns_path: True if the method returns a path, and thus we 172 must compensate for expected difference between real and fake. 173 174 Returns: 175 A description of the difference in behavior, or None. 176 """ 177 # pylint: disable=C6403 178 179 def _error_class(exc): 180 if exc: 181 if hasattr(exc, "errno"): 182 return "{}({})".format(exc.__class__.__name__, exc.errno) 183 return exc.__class__.__name__ 184 return "None" 185 186 real_err, real_value = self._get_real_value(method_name, path, real) 187 fake_err, fake_value = self._get_fake_value(method_name, path, fake) 188 189 method_call = f"{method_name}" 190 method_call += "()" if path == () else "({path})" 191 # We only compare on the error class because the actual error contents 192 # is almost always different because of the file paths. 193 if _error_class(real_err) != _error_class(fake_err): 194 if real_err is None: 195 return "%s: real version returned %s, fake raised %s" % ( 196 method_call, 197 real_value, 198 _error_class(fake_err), 199 ) 200 if fake_err is None: 201 return "%s: real version raised %s, fake returned %s" % ( 202 method_call, 203 _error_class(real_err), 204 fake_value, 205 ) 206 return "%s: real version raised %s, fake raised %s" % ( 207 method_call, 208 _error_class(real_err), 209 _error_class(fake_err), 210 ) 211 real_errno = _get_errno(real_err) 212 fake_errno = _get_errno(fake_err) 213 if real_errno != fake_errno: 214 return "%s(%s): both raised %s, real errno %s, fake errno %s" % ( 215 method_name, 216 path, 217 _error_class(real_err), 218 real_errno, 219 fake_errno, 220 ) 221 # If the method is supposed to return a full path AND both values 222 # begin with the expected full path, then trim it off. 223 if method_returns_path: 224 if ( 225 real_value 226 and fake_value 227 and real_value.startswith(self.real_base) 228 and fake_value.startswith(self.fake_base) 229 ): 230 real_value = real_value[len(self.real_base) :] 231 fake_value = fake_value[len(self.fake_base) :] 232 if real_value != fake_value: 233 return "%s: real return %s, fake returned %s" % ( 234 method_call, 235 real_value, 236 fake_value, 237 ) 238 return None 239 240 @staticmethod 241 def _get_fake_value(method_name, path, fake): 242 fake_value = None 243 fake_err = None 244 try: 245 fake_method = fake 246 if not callable(fake): 247 fake_method = getattr(fake, method_name) 248 args = [] if path == () else [path] 249 result = fake_method(*args) 250 if isinstance(result, bytes): 251 fake_value = result.decode() 252 else: 253 fake_value = str(result) 254 except Exception as e: # pylint: disable-msg=W0703 255 fake_err = e 256 return fake_err, fake_value 257 258 @staticmethod 259 def _get_real_value(method_name, path, real): 260 real_value = None 261 real_err = None 262 # Catching Exception below gives a lint warning, but it's what we need. 263 try: 264 args = [] if path == () else [path] 265 real_method = real 266 if not callable(real): 267 real_method = getattr(real, method_name) 268 result = real_method(*args) 269 if isinstance(result, bytes): 270 real_value = result.decode() 271 else: 272 real_value = str(result) 273 except Exception as e: # pylint: disable-msg=W0703 274 real_err = e 275 return real_err, real_value 276 277 def assertOsMethodBehaviorMatches( 278 self, method_name, path, method_returns_path=False 279 ): 280 """Invoke an os method in both real and fake contexts and compare. 281 282 For a given method name (from the os module) and a path, compare the 283 behavior of the system provided module against the fake_filesystem 284 module. 285 We expect results and/or Exceptions raised to be identical. 286 287 Args: 288 method_name: Name of method being tested. 289 path: potential path to a file in the real and fake file systems. 290 method_returns_path: True if the method returns a path, and thus we 291 must compensate for expected difference between real and fake. 292 293 Returns: 294 A description of the difference in behavior, or None. 295 """ 296 path = sep(path) 297 return self._compare_behaviors( 298 method_name, path, os, self.fake_os, method_returns_path 299 ) 300 301 def diff_open_method_behavior( 302 self, method_name, path, mode, data, method_returns_data=True 303 ): 304 """Invoke an open method in both real and fkae contexts and compare. 305 306 Args: 307 method_name: Name of method being tested. 308 path: potential path to a file in the real and fake file systems. 309 mode: how to open the file. 310 data: any data to pass to the method. 311 method_returns_data: True if a method returns some sort of data. 312 313 For a given method name (from builtin open) and a path, compare the 314 behavior of the system provided module against the fake_filesystem 315 module. 316 We expect results and/or Exceptions raised to be identical. 317 318 Returns: 319 A description of the difference in behavior, or None. 320 """ 321 with open(path, mode) as real_fh: 322 with self.fake_open(path, mode) as fake_fh: 323 return self._compare_behaviors( 324 method_name, data, real_fh, fake_fh, method_returns_data 325 ) 326 327 def diff_os_path_method_behavior( 328 self, method_name, path, method_returns_path=False 329 ): 330 """Invoke an os.path method in both real and fake contexts and compare. 331 332 For a given method name (from the os.path module) and a path, compare 333 the behavior of the system provided module against the 334 fake_filesytem module. 335 We expect results and/or Exceptions raised to be identical. 336 337 Args: 338 method_name: Name of method being tested. 339 path: potential path to a file in the real and fake file systems. 340 method_returns_path: True if the method returns a path, and thus we 341 must compensate for expected difference between real and fake. 342 343 Returns: 344 A description of the difference in behavior, or None. 345 """ 346 return self._compare_behaviors( 347 method_name, path, os.path, self.fake_os.path, method_returns_path 348 ) 349 350 def assertOsPathMethodBehaviorMatches( 351 self, method_name, path, method_returns_path=False 352 ): 353 """Assert that an os.path behaves the same in both real and 354 fake contexts. 355 356 Wraps DiffOsPathMethodBehavior, raising AssertionError if any 357 differences are reported. 358 359 Args: 360 method_name: Name of method being tested. 361 path: potential path to a file in the real and fake file systems. 362 method_returns_path: True if the method returns a path, and thus we 363 must compensate for expected difference between real and fake. 364 365 Raises: 366 AssertionError if there is any difference in behavior. 367 """ 368 path = sep(path) 369 diff = self.diff_os_path_method_behavior(method_name, path, method_returns_path) 370 if diff: 371 self.fail(diff) 372 373 def assertAllOsBehaviorsMatch(self, path): 374 path = sep(path) 375 os_method_names = [] if self.is_windows else ["readlink"] 376 os_method_names_no_args = ["getcwd"] 377 os_path_method_names = ["isabs", "isdir"] 378 if not self.is_windows: 379 os_path_method_names += ["islink", "lexists"] 380 if not self.is_windows or not IS_PYPY: 381 os_path_method_names += ["isfile", "exists"] 382 383 wrapped_methods = [ 384 ["access", self._access_real, self._access_fake], 385 ["stat.size", self._stat_size_real, self._stat_size_fake], 386 ["lstat.size", self._lstat_size_real, self._lstat_size_fake], 387 ] 388 389 differences = [] 390 for method_name in os_method_names: 391 diff = self.assertOsMethodBehaviorMatches(method_name, path) 392 if diff: 393 differences.append(diff) 394 for method_name in os_method_names_no_args: 395 diff = self.assertOsMethodBehaviorMatches( 396 method_name, (), method_returns_path=True 397 ) 398 if diff: 399 differences.append(diff) 400 for method_name in os_path_method_names: 401 diff = self.diff_os_path_method_behavior(method_name, path) 402 if diff: 403 differences.append(diff) 404 for m in wrapped_methods: 405 diff = self._compare_behaviors(m[0], path, m[1], m[2]) 406 if diff: 407 differences.append(diff) 408 if differences: 409 self.fail( 410 "Behaviors do not match for %s:\n %s" 411 % (path, "\n ".join(differences)) 412 ) 413 414 def assertFileHandleBehaviorsMatch(self, path, mode, data): 415 path = sep(path) 416 write_method_names = ["write", "writelines"] 417 read_method_names = ["read", "readlines"] 418 other_method_names = ["truncate", "flush", "close"] 419 differences = [] 420 for method_name in write_method_names: 421 diff = self.diff_open_method_behavior(method_name, path, mode, data) 422 if diff: 423 differences.append(diff) 424 for method_name in read_method_names + other_method_names: 425 diff = self.diff_open_method_behavior(method_name, path, mode, ()) 426 if diff: 427 differences.append(diff) 428 if differences: 429 self.fail( 430 "Behaviors do not match for %s:\n %s" 431 % (path, "\n ".join(differences)) 432 ) 433 434 def assertFileHandleOpenBehaviorsMatch(self, *args, **kwargs): 435 """Compare open() function invocation between real and fake. 436 437 Runs open(*args, **kwargs) on both real and fake. 438 439 Args: 440 *args: args to pass through to open() 441 **kwargs: kwargs to pass through to open(). 442 443 Returns: 444 None. 445 446 Raises: 447 AssertionError if underlying open() behavior differs from fake. 448 """ 449 real_err = None 450 fake_err = None 451 try: 452 with open(*args, **kwargs): 453 pass 454 except Exception as e: # pylint: disable-msg=W0703 455 real_err = e 456 457 try: 458 with self.fake_open(*args, **kwargs): 459 pass 460 except Exception as e: # pylint: disable-msg=W0703 461 fake_err = e 462 463 # default equal in case one is None and other is not. 464 is_exception_equal = real_err == fake_err 465 if real_err and fake_err: 466 # exception __eq__ doesn't evaluate equal ever, thus manual check. 467 is_exception_equal = ( 468 type(real_err) is type(fake_err) and real_err.args == fake_err.args 469 ) 470 471 if not is_exception_equal: 472 msg = "Behaviors don't match on open with args %s & kwargs %s.\n" % ( 473 args, 474 kwargs, 475 ) 476 real_err_msg = "Real open results in: %s\n" % repr(real_err) 477 fake_err_msg = "Fake open results in: %s\n" % repr(fake_err) 478 self.fail(msg + real_err_msg + fake_err_msg) 479 480 # Helpers for checks which are not straight method calls. 481 @staticmethod 482 def _access_real(path): 483 return os.access(path, os.R_OK) 484 485 def _access_fake(self, path): 486 return self.fake_os.access(path, os.R_OK) 487 488 def _stat_size_real(self, path): 489 real_path, unused_fake_path = self._paths(path) 490 # fake_filesystem.py does not implement stat().st_size for directories 491 if os.path.isdir(real_path): 492 return None 493 return os.stat(real_path).st_size 494 495 def _stat_size_fake(self, path): 496 unused_real_path, fake_path = self._paths(path) 497 # fake_filesystem.py does not implement stat().st_size for directories 498 if self.fake_os.path.isdir(fake_path): 499 return None 500 return self.fake_os.stat(fake_path).st_size 501 502 def _lstat_size_real(self, path): 503 real_path, unused_fake_path = self._paths(path) 504 if os.path.isdir(real_path): 505 return None 506 size = os.lstat(real_path).st_size 507 # Account for the difference in the lengths of the absolute paths. 508 if os.path.islink(real_path): 509 if os.readlink(real_path).startswith(os.sep): 510 size -= len(self.real_base) 511 return size 512 513 def _lstat_size_fake(self, path): 514 unused_real_path, fake_path = self._paths(path) 515 # size = 0 516 if self.fake_os.path.isdir(fake_path): 517 return None 518 size = self.fake_os.lstat(fake_path).st_size 519 # Account for the difference in the lengths of the absolute paths. 520 if self.fake_os.path.islink(fake_path): 521 if self.fake_os.readlink(fake_path).startswith(os.sep): 522 size -= len(self.fake_base) 523 return size 524 525 def test_isabs(self): 526 # We do not have to create any files for isabs. 527 self.assertOsPathMethodBehaviorMatches("isabs", None) 528 self.assertOsPathMethodBehaviorMatches("isabs", "") 529 self.assertOsPathMethodBehaviorMatches("isabs", "/") 530 self.assertOsPathMethodBehaviorMatches("isabs", "/a") 531 self.assertOsPathMethodBehaviorMatches("isabs", "a") 532 533 def test_none_path(self): 534 self.assertAllOsBehaviorsMatch(None) 535 536 def test_empty_path(self): 537 self.assertAllOsBehaviorsMatch("") 538 539 def test_root_path(self): 540 self.assertAllOsBehaviorsMatch("/") 541 542 def test_non_existant_file(self): 543 self.assertAllOsBehaviorsMatch("foo") 544 545 def test_empty_file(self): 546 self._create_test_file("f", "aFile") 547 self.assertAllOsBehaviorsMatch("aFile") 548 549 def test_file_with_contents(self): 550 self._create_test_file("f", "aFile", "some contents") 551 self.assertAllOsBehaviorsMatch("aFile") 552 553 def test_file_with_binary_contents(self): 554 self._create_test_file("b", "aFile", b"some contents") 555 self.assertAllOsBehaviorsMatch("aFile") 556 557 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 558 def test_sym_link_to_empty_file(self): 559 self._create_test_file("f", "aFile") 560 self._create_test_file("l", "link_to_empty", "aFile") 561 self.assertAllOsBehaviorsMatch("link_to_empty") 562 563 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 564 def test_hard_link_to_empty_file(self): 565 self._create_test_file("f", "aFile") 566 self._create_test_file("h", "link_to_empty", "aFile") 567 self.assertAllOsBehaviorsMatch("link_to_empty") 568 569 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 570 def test_sym_link_to_real_file(self): 571 self._create_test_file("f", "aFile", "some contents") 572 self._create_test_file("l", "link_to_file", "aFile") 573 self.assertAllOsBehaviorsMatch("link_to_file") 574 575 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 576 def test_hard_link_to_real_file(self): 577 self._create_test_file("f", "aFile", "some contents") 578 self._create_test_file("h", "link_to_file", "aFile") 579 self.assertAllOsBehaviorsMatch("link_to_file") 580 581 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 582 def test_broken_sym_link(self): 583 self._create_test_file("l", "broken_link", "broken") 584 self._create_test_file("l", "loop", "/a/loop") 585 self.assertAllOsBehaviorsMatch("broken_link") 586 587 def test_file_in_a_folder(self): 588 self._create_test_file("d", "a") 589 self._create_test_file("d", "a/b") 590 self._create_test_file("f", "a/b/file", "contents") 591 self.assertAllOsBehaviorsMatch("a/b/file") 592 593 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 594 def test_absolute_sym_link_to_folder(self): 595 self._create_test_file("d", "a") 596 self._create_test_file("d", "a/b") 597 self._create_test_file("f", "a/b/file", "contents") 598 self._create_test_file("l", "a/link", "/a/b") 599 self.assertAllOsBehaviorsMatch("a/link/file") 600 601 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 602 def test_link_to_folder_after_chdir(self): 603 self._create_test_file("d", "a") 604 self._create_test_file("d", "a/b") 605 self._create_test_file("f", "a/b/file", "contents") 606 self._create_test_file("l", "a/link", "/a/b") 607 608 real_dir, fake_dir = self._paths("a/b") 609 os.chdir(real_dir) 610 self.fake_os.chdir(fake_dir) 611 self.assertAllOsBehaviorsMatch("file") 612 613 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 614 def test_relative_sym_link_to_folder(self): 615 self._create_test_file("d", "a") 616 self._create_test_file("d", "a/b") 617 self._create_test_file("f", "a/b/file", "contents") 618 self._create_test_file("l", "a/link", "b") 619 self.assertAllOsBehaviorsMatch("a/link/file") 620 621 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 622 def test_sym_link_to_parent(self): 623 # Soft links on HFS+ / OS X behave differently. 624 if os.uname()[0] != "Darwin": 625 self._create_test_file("d", "a") 626 self._create_test_file("d", "a/b") 627 self._create_test_file("l", "a/b/c", "..") 628 self.assertAllOsBehaviorsMatch("a/b/c") 629 630 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 631 def test_path_through_sym_link_to_parent(self): 632 self._create_test_file("d", "a") 633 self._create_test_file("f", "a/target", "contents") 634 self._create_test_file("d", "a/b") 635 self._create_test_file("l", "a/b/c", "..") 636 self.assertAllOsBehaviorsMatch("a/b/c/target") 637 638 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 639 def test_sym_link_to_sibling_directory(self): 640 self._create_test_file("d", "a") 641 self._create_test_file("d", "a/b") 642 self._create_test_file("d", "a/sibling_of_b") 643 self._create_test_file("f", "a/sibling_of_b/target", "contents") 644 self._create_test_file("l", "a/b/c", "../sibling_of_b") 645 self.assertAllOsBehaviorsMatch("a/b/c/target") 646 647 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 648 def test_sym_link_to_sibling_directory_non_existant_file(self): 649 self._create_test_file("d", "a") 650 self._create_test_file("d", "a/b") 651 self._create_test_file("d", "a/sibling_of_b") 652 self._create_test_file("f", "a/sibling_of_b/target", "contents") 653 self._create_test_file("l", "a/b/c", "../sibling_of_b") 654 self.assertAllOsBehaviorsMatch("a/b/c/file_does_not_exist") 655 656 @unittest.skipIf(TestCase.is_windows, "no symlink in Windows") 657 def test_broken_sym_link_to_sibling_directory(self): 658 self._create_test_file("d", "a") 659 self._create_test_file("d", "a/b") 660 self._create_test_file("d", "a/sibling_of_b") 661 self._create_test_file("f", "a/sibling_of_b/target", "contents") 662 self._create_test_file("l", "a/b/c", "../broken_sibling_of_b") 663 self.assertAllOsBehaviorsMatch("a/b/c/target") 664 665 def test_relative_path(self): 666 self._create_test_file("d", "a") 667 self._create_test_file("d", "a/b") 668 self._create_test_file("d", "a/sibling_of_b") 669 self._create_test_file("f", "a/sibling_of_b/target", "contents") 670 self.assertAllOsBehaviorsMatch("a/b/../sibling_of_b/target") 671 672 def test_broken_relative_path(self): 673 self._create_test_file("d", "a") 674 self._create_test_file("d", "a/b") 675 self._create_test_file("d", "a/sibling_of_b") 676 self._create_test_file("f", "a/sibling_of_b/target", "contents") 677 self.assertAllOsBehaviorsMatch("a/b/../broken/target") 678 679 def test_bad_relative_path(self): 680 self._create_test_file("d", "a") 681 self._create_test_file("f", "a/target", "contents") 682 self._create_test_file("d", "a/b") 683 self._create_test_file("d", "a/sibling_of_b") 684 self._create_test_file("f", "a/sibling_of_b/target", "contents") 685 self.assertAllOsBehaviorsMatch("a/b/../broken/../target") 686 687 def test_getmtime_nonexistant_path(self): 688 self.assertOsPathMethodBehaviorMatches("getmtime", "no/such/path") 689 690 def test_builtin_open_modes(self): 691 self._create_test_file("f", "read", "some contents") 692 self._create_test_file("f", "write", "some contents") 693 self._create_test_file("f", "append", "some contents") 694 self.assertFileHandleBehaviorsMatch("read", "r", "other contents") 695 self.assertFileHandleBehaviorsMatch("write", "w", "other contents") 696 self.assertFileHandleBehaviorsMatch("append", "a", "other contents") 697 self._create_test_file("f", "readplus", "some contents") 698 self._create_test_file("f", "writeplus", "some contents") 699 self.assertFileHandleBehaviorsMatch("readplus", "r+", "other contents") 700 self.assertFileHandleBehaviorsMatch("writeplus", "w+", "other contents") 701 self._create_test_file("b", "binaryread", b"some contents") 702 self._create_test_file("b", "binarywrite", b"some contents") 703 self._create_test_file("b", "binaryappend", b"some contents") 704 self.assertFileHandleBehaviorsMatch("binaryread", "rb", b"other contents") 705 self.assertFileHandleBehaviorsMatch("binarywrite", "wb", b"other contents") 706 self.assertFileHandleBehaviorsMatch("binaryappend", "ab", b"other contents") 707 self.assertFileHandleBehaviorsMatch("read", "rb", "other contents") 708 self.assertFileHandleBehaviorsMatch("write", "wb", "other contents") 709 self.assertFileHandleBehaviorsMatch("append", "ab", "other contents") 710 711 # binary cannot have encoding 712 self.assertFileHandleOpenBehaviorsMatch("read", "rb", encoding="enc") 713 self.assertFileHandleOpenBehaviorsMatch("write", mode="wb", encoding="enc") 714 self.assertFileHandleOpenBehaviorsMatch("append", "ab", encoding="enc") 715 716 # text can have encoding 717 self.assertFileHandleOpenBehaviorsMatch("read", "r", encoding="utf-8") 718 self.assertFileHandleOpenBehaviorsMatch("write", "w", encoding="utf-8") 719 self.assertFileHandleOpenBehaviorsMatch("append", "a", encoding="utf-8") 720 721 722def main(_): 723 unittest.main() 724 725 726if __name__ == "__main__": 727 unittest.main() 728