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