| # Copyright 2009 Google Inc. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Test that FakeFilesystem calls work identically to a real filesystem.""" |
| # pylint: disable-all |
| |
| import os |
| import shutil |
| import sys |
| import tempfile |
| import time |
| import unittest |
| |
| from pyfakefs import fake_filesystem |
| from pyfakefs.helpers import IS_PYPY |
| |
| |
| def sep(path): |
| """Converts slashes in the path to the architecture's path seperator.""" |
| if isinstance(path, str): |
| return path.replace('/', os.sep) |
| return path |
| |
| |
| def _get_errno(raised_error): |
| if raised_error is not None: |
| try: |
| return raised_error.errno |
| except AttributeError: |
| pass |
| |
| |
| class TestCase(unittest.TestCase): |
| is_windows = sys.platform.startswith('win') |
| _FAKE_FS_BASE = sep('/fakefs') |
| |
| |
| class FakeFilesystemVsRealTest(TestCase): |
| def _paths(self, path): |
| """For a given path, return paths in the real and fake filesystems.""" |
| if not path: |
| return None, None |
| return (os.path.join(self.real_base, path), |
| os.path.join(self.fake_base, path)) |
| |
| def _create_test_file(self, file_type, path, contents=None): |
| """Create a dir, file, or link in both the real fs and the fake.""" |
| path = sep(path) |
| self._created_files.append([file_type, path, contents]) |
| real_path, fake_path = self._paths(path) |
| if file_type == 'd': |
| os.mkdir(real_path) |
| self.fake_os.mkdir(fake_path) |
| if file_type == 'f': |
| fh = open(real_path, 'w') |
| fh.write(contents or '') |
| fh.close() |
| fh = self.fake_open(fake_path, 'w') |
| fh.write(contents or '') |
| fh.close() |
| # b for binary file |
| if file_type == 'b': |
| fh = open(real_path, 'wb') |
| fh.write(contents or '') |
| fh.close() |
| fh = self.fake_open(fake_path, 'wb') |
| fh.write(contents or '') |
| fh.close() |
| # l for symlink, h for hard link |
| if file_type in ('l', 'h'): |
| real_target, fake_target = (contents, contents) |
| # If it begins with '/', make it relative to the base. You can't go |
| # creating files in / for the real file system. |
| if contents.startswith(os.sep): |
| real_target, fake_target = self._paths(contents[1:]) |
| if file_type == 'l': |
| os.symlink(real_target, real_path) |
| self.fake_os.symlink(fake_target, fake_path) |
| elif file_type == 'h': |
| os.link(real_target, real_path) |
| self.fake_os.link(fake_target, fake_path) |
| |
| def setUp(self): |
| # Base paths in the real and test file systems. We keep them different |
| # so that missing features in the fake don't fall through to the base |
| # operations and magically succeed. |
| tsname = 'fakefs.%s' % time.time() |
| self.cwd = os.getcwd() |
| # Fully expand the base_path - required on OS X. |
| self.real_base = os.path.realpath( |
| os.path.join(tempfile.gettempdir(), tsname)) |
| os.chdir(tempfile.gettempdir()) |
| if os.path.isdir(self.real_base): |
| shutil.rmtree(self.real_base) |
| os.mkdir(self.real_base) |
| self.fake_base = self._FAKE_FS_BASE |
| |
| # Make sure we can write to the physical testing temp directory. |
| self.assertTrue(os.access(self.real_base, os.W_OK)) |
| |
| self.fake_filesystem = fake_filesystem.FakeFilesystem() |
| self.fake_filesystem.create_dir(self.fake_base) |
| self.fake_os = fake_filesystem.FakeOsModule(self.fake_filesystem) |
| self.fake_open = fake_filesystem.FakeFileOpen(self.fake_filesystem) |
| self._created_files = [] |
| |
| os.chdir(self.real_base) |
| self.fake_os.chdir(self.fake_base) |
| |
| def tearDown(self): |
| # We have to remove all the files from the real FS. Doing the same for |
| # the fake FS is optional, but doing it is an extra sanity check. |
| os.chdir(tempfile.gettempdir()) |
| try: |
| rev_files = self._created_files[:] |
| rev_files.reverse() |
| for info in rev_files: |
| real_path, fake_path = self._paths(info[1]) |
| if info[0] == 'd': |
| try: |
| os.rmdir(real_path) |
| except OSError as e: |
| if 'Directory not empty' in e: |
| self.fail('Real path %s not empty: %s : %s' % ( |
| real_path, e, os.listdir(real_path))) |
| else: |
| raise |
| self.fake_os.rmdir(fake_path) |
| if info[0] == 'f' or info[0] == 'l': |
| os.remove(real_path) |
| self.fake_os.remove(fake_path) |
| finally: |
| shutil.rmtree(self.real_base) |
| os.chdir(self.cwd) |
| |
| def _compare_behaviors(self, method_name, path, real, fake, |
| method_returns_path=False): |
| """Invoke an os method in both real and fake contexts and compare |
| results. |
| |
| Invoke a real filesystem method with a path to a real file and invoke |
| a fake filesystem method with a path to a fake file and compare the |
| results. We expect some calls to throw Exceptions, so we catch those |
| and compare them. |
| |
| Args: |
| method_name: Name of method being tested, for use in |
| error messages. |
| path: potential path to a file in the real and fake file systems, |
| passing an empty tuple indicates that no arguments to pass |
| to method. |
| real: built-in system library or method from the built-in system |
| library which takes a path as an arg and returns some value. |
| fake: fake_filsystem object or method from a fake_filesystem class |
| which takes a path as an arg and returns some value. |
| method_returns_path: True if the method returns a path, and thus we |
| must compensate for expected difference between real and fake. |
| |
| Returns: |
| A description of the difference in behavior, or None. |
| """ |
| # pylint: disable=C6403 |
| |
| def _error_class(exc): |
| if exc: |
| if hasattr(exc, 'errno'): |
| return '{}({})'.format(exc.__class__.__name__, exc.errno) |
| return exc.__class__.__name__ |
| return 'None' |
| |
| real_err, real_value = self._get_real_value(method_name, path, real) |
| fake_err, fake_value = self._get_fake_value(method_name, path, fake) |
| |
| method_call = f'{method_name}' |
| method_call += '()' if path == () else '({path})' |
| # We only compare on the error class because the acutal error contents |
| # is almost always different because of the file paths. |
| if _error_class(real_err) != _error_class(fake_err): |
| if real_err is None: |
| return '%s: real version returned %s, fake raised %s' % ( |
| method_call, real_value, _error_class(fake_err)) |
| if fake_err is None: |
| return '%s: real version raised %s, fake returned %s' % ( |
| method_call, _error_class(real_err), fake_value) |
| return '%s: real version raised %s, fake raised %s' % ( |
| method_call, _error_class(real_err), _error_class(fake_err)) |
| real_errno = _get_errno(real_err) |
| fake_errno = _get_errno(fake_err) |
| if real_errno != fake_errno: |
| return '%s(%s): both raised %s, real errno %s, fake errno %s' % ( |
| method_name, path, _error_class(real_err), |
| real_errno, fake_errno) |
| # If the method is supposed to return a full path AND both values |
| # begin with the expected full path, then trim it off. |
| if method_returns_path: |
| if (real_value and fake_value |
| and real_value.startswith(self.real_base) |
| and fake_value.startswith(self.fake_base)): |
| real_value = real_value[len(self.real_base):] |
| fake_value = fake_value[len(self.fake_base):] |
| if real_value != fake_value: |
| return '%s: real return %s, fake returned %s' % ( |
| method_call, real_value, fake_value) |
| return None |
| |
| @staticmethod |
| def _get_fake_value(method_name, path, fake): |
| fake_value = None |
| fake_err = None |
| try: |
| fake_method = fake |
| if not callable(fake): |
| fake_method = getattr(fake, method_name) |
| args = [] if path == () else [path] |
| result = fake_method(*args) |
| if isinstance(result, bytes): |
| fake_value = result.decode() |
| else: |
| fake_value = str(result) |
| except Exception as e: # pylint: disable-msg=W0703 |
| fake_err = e |
| return fake_err, fake_value |
| |
| @staticmethod |
| def _get_real_value(method_name, path, real): |
| real_value = None |
| real_err = None |
| # Catching Exception below gives a lint warning, but it's what we need. |
| try: |
| args = [] if path == () else [path] |
| real_method = real |
| if not callable(real): |
| real_method = getattr(real, method_name) |
| result = real_method(*args) |
| if isinstance(result, bytes): |
| real_value = result.decode() |
| else: |
| real_value = str(result) |
| except Exception as e: # pylint: disable-msg=W0703 |
| real_err = e |
| return real_err, real_value |
| |
| def assertOsMethodBehaviorMatches(self, method_name, path, |
| method_returns_path=False): |
| """Invoke an os method in both real and fake contexts and compare. |
| |
| For a given method name (from the os module) and a path, compare the |
| behavior of the system provided module against the fake_filesystem |
| module. |
| We expect results and/or Exceptions raised to be identical. |
| |
| Args: |
| method_name: Name of method being tested. |
| path: potential path to a file in the real and fake file systems. |
| method_returns_path: True if the method returns a path, and thus we |
| must compensate for expected difference between real and fake. |
| |
| Returns: |
| A description of the difference in behavior, or None. |
| """ |
| path = sep(path) |
| return self._compare_behaviors(method_name, path, os, self.fake_os, |
| method_returns_path) |
| |
| def diff_open_method_behavior(self, method_name, path, mode, data, |
| method_returns_data=True): |
| """Invoke an open method in both real and fkae contexts and compare. |
| |
| Args: |
| method_name: Name of method being tested. |
| path: potential path to a file in the real and fake file systems. |
| mode: how to open the file. |
| data: any data to pass to the method. |
| method_returns_data: True if a method returns some sort of data. |
| |
| For a given method name (from builtin open) and a path, compare the |
| behavior of the system provided module against the fake_filesystem |
| module. |
| We expect results and/or Exceptions raised to be identical. |
| |
| Returns: |
| A description of the difference in behavior, or None. |
| """ |
| with open(path, mode) as real_fh: |
| with self.fake_open(path, mode) as fake_fh: |
| return self._compare_behaviors( |
| method_name, data, real_fh, fake_fh, method_returns_data) |
| |
| def diff_os_path_method_behavior(self, method_name, path, |
| method_returns_path=False): |
| """Invoke an os.path method in both real and fake contexts and compare. |
| |
| For a given method name (from the os.path module) and a path, compare |
| the behavior of the system provided module against the |
| fake_filesytem module. |
| We expect results and/or Exceptions raised to be identical. |
| |
| Args: |
| method_name: Name of method being tested. |
| path: potential path to a file in the real and fake file systems. |
| method_returns_path: True if the method returns a path, and thus we |
| must compensate for expected difference between real and fake. |
| |
| Returns: |
| A description of the difference in behavior, or None. |
| """ |
| return self._compare_behaviors(method_name, path, os.path, |
| self.fake_os.path, |
| method_returns_path) |
| |
| def assertOsPathMethodBehaviorMatches(self, method_name, path, |
| method_returns_path=False): |
| """Assert that an os.path behaves the same in both real and |
| fake contexts. |
| |
| Wraps DiffOsPathMethodBehavior, raising AssertionError if any |
| differences are reported. |
| |
| Args: |
| method_name: Name of method being tested. |
| path: potential path to a file in the real and fake file systems. |
| method_returns_path: True if the method returns a path, and thus we |
| must compensate for expected difference between real and fake. |
| |
| Raises: |
| AssertionError if there is any difference in behavior. |
| """ |
| path = sep(path) |
| diff = self.diff_os_path_method_behavior( |
| method_name, path, method_returns_path) |
| if diff: |
| self.fail(diff) |
| |
| def assertAllOsBehaviorsMatch(self, path): |
| path = sep(path) |
| os_method_names = [] if self.is_windows else ['readlink'] |
| os_method_names_no_args = ['getcwd'] |
| os_path_method_names = ['isabs', 'isdir'] |
| if not self.is_windows: |
| os_path_method_names += ['islink', 'lexists'] |
| if not self.is_windows or not IS_PYPY: |
| os_path_method_names += ['isfile', 'exists'] |
| |
| wrapped_methods = [ |
| ['access', self._access_real, self._access_fake], |
| ['stat.size', self._stat_size_real, self._stat_size_fake], |
| ['lstat.size', self._lstat_size_real, self._lstat_size_fake] |
| ] |
| |
| differences = [] |
| for method_name in os_method_names: |
| diff = self.assertOsMethodBehaviorMatches(method_name, path) |
| if diff: |
| differences.append(diff) |
| for method_name in os_method_names_no_args: |
| diff = self.assertOsMethodBehaviorMatches(method_name, (), |
| method_returns_path=True) |
| if diff: |
| differences.append(diff) |
| for method_name in os_path_method_names: |
| diff = self.diff_os_path_method_behavior(method_name, path) |
| if diff: |
| differences.append(diff) |
| for m in wrapped_methods: |
| diff = self._compare_behaviors(m[0], path, m[1], m[2]) |
| if diff: |
| differences.append(diff) |
| if differences: |
| self.fail('Behaviors do not match for %s:\n %s' % |
| (path, '\n '.join(differences))) |
| |
| def assertFileHandleBehaviorsMatch(self, path, mode, data): |
| path = sep(path) |
| write_method_names = ['write', 'writelines'] |
| read_method_names = ['read', 'readlines'] |
| other_method_names = ['truncate', 'flush', 'close'] |
| differences = [] |
| for method_name in write_method_names: |
| diff = self.diff_open_method_behavior( |
| method_name, path, mode, data) |
| if diff: |
| differences.append(diff) |
| for method_name in read_method_names + other_method_names: |
| diff = self.diff_open_method_behavior(method_name, path, mode, ()) |
| if diff: |
| differences.append(diff) |
| if differences: |
| self.fail('Behaviors do not match for %s:\n %s' % |
| (path, '\n '.join(differences))) |
| |
| def assertFileHandleOpenBehaviorsMatch(self, *args, **kwargs): |
| """Compare open() function invocation between real and fake. |
| |
| Runs open(*args, **kwargs) on both real and fake. |
| |
| Args: |
| *args: args to pass through to open() |
| **kwargs: kwargs to pass through to open(). |
| |
| Returns: |
| None. |
| |
| Raises: |
| AssertionError if underlying open() behavior differs from fake. |
| """ |
| real_err = None |
| fake_err = None |
| try: |
| with open(*args, **kwargs): |
| pass |
| except Exception as e: # pylint: disable-msg=W0703 |
| real_err = e |
| |
| try: |
| with self.fake_open(*args, **kwargs): |
| pass |
| except Exception as e: # pylint: disable-msg=W0703 |
| fake_err = e |
| |
| # default equal in case one is None and other is not. |
| is_exception_equal = (real_err == fake_err) |
| if real_err and fake_err: |
| # exception __eq__ doesn't evaluate equal ever, thus manual check. |
| is_exception_equal = (type(real_err) is type(fake_err) and |
| real_err.args == fake_err.args) |
| |
| if not is_exception_equal: |
| msg = ( |
| "Behaviors don't match on open with args %s & kwargs %s.\n" % |
| (args, kwargs)) |
| real_err_msg = 'Real open results in: %s\n' % repr(real_err) |
| fake_err_msg = 'Fake open results in: %s\n' % repr(fake_err) |
| self.fail(msg + real_err_msg + fake_err_msg) |
| |
| # Helpers for checks which are not straight method calls. |
| @staticmethod |
| def _access_real(path): |
| return os.access(path, os.R_OK) |
| |
| def _access_fake(self, path): |
| return self.fake_os.access(path, os.R_OK) |
| |
| def _stat_size_real(self, path): |
| real_path, unused_fake_path = self._paths(path) |
| # fake_filesystem.py does not implement stat().st_size for directories |
| if os.path.isdir(real_path): |
| return None |
| return os.stat(real_path).st_size |
| |
| def _stat_size_fake(self, path): |
| unused_real_path, fake_path = self._paths(path) |
| # fake_filesystem.py does not implement stat().st_size for directories |
| if self.fake_os.path.isdir(fake_path): |
| return None |
| return self.fake_os.stat(fake_path).st_size |
| |
| def _lstat_size_real(self, path): |
| real_path, unused_fake_path = self._paths(path) |
| if os.path.isdir(real_path): |
| return None |
| size = os.lstat(real_path).st_size |
| # Account for the difference in the lengths of the absolute paths. |
| if os.path.islink(real_path): |
| if os.readlink(real_path).startswith(os.sep): |
| size -= len(self.real_base) |
| return size |
| |
| def _lstat_size_fake(self, path): |
| unused_real_path, fake_path = self._paths(path) |
| # size = 0 |
| if self.fake_os.path.isdir(fake_path): |
| return None |
| size = self.fake_os.lstat(fake_path).st_size |
| # Account for the difference in the lengths of the absolute paths. |
| if self.fake_os.path.islink(fake_path): |
| if self.fake_os.readlink(fake_path).startswith(os.sep): |
| size -= len(self.fake_base) |
| return size |
| |
| def test_isabs(self): |
| # We do not have to create any files for isabs. |
| self.assertOsPathMethodBehaviorMatches('isabs', None) |
| self.assertOsPathMethodBehaviorMatches('isabs', '') |
| self.assertOsPathMethodBehaviorMatches('isabs', '/') |
| self.assertOsPathMethodBehaviorMatches('isabs', '/a') |
| self.assertOsPathMethodBehaviorMatches('isabs', 'a') |
| |
| def test_none_path(self): |
| self.assertAllOsBehaviorsMatch(None) |
| |
| def test_empty_path(self): |
| self.assertAllOsBehaviorsMatch('') |
| |
| def test_root_path(self): |
| self.assertAllOsBehaviorsMatch('/') |
| |
| def test_non_existant_file(self): |
| self.assertAllOsBehaviorsMatch('foo') |
| |
| def test_empty_file(self): |
| self._create_test_file('f', 'aFile') |
| self.assertAllOsBehaviorsMatch('aFile') |
| |
| def test_file_with_contents(self): |
| self._create_test_file('f', 'aFile', 'some contents') |
| self.assertAllOsBehaviorsMatch('aFile') |
| |
| def test_file_with_binary_contents(self): |
| self._create_test_file('b', 'aFile', b'some contents') |
| self.assertAllOsBehaviorsMatch('aFile') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_sym_link_to_empty_file(self): |
| self._create_test_file('f', 'aFile') |
| self._create_test_file('l', 'link_to_empty', 'aFile') |
| self.assertAllOsBehaviorsMatch('link_to_empty') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_hard_link_to_empty_file(self): |
| self._create_test_file('f', 'aFile') |
| self._create_test_file('h', 'link_to_empty', 'aFile') |
| self.assertAllOsBehaviorsMatch('link_to_empty') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_sym_link_to_real_file(self): |
| self._create_test_file('f', 'aFile', 'some contents') |
| self._create_test_file('l', 'link_to_file', 'aFile') |
| self.assertAllOsBehaviorsMatch('link_to_file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_hard_link_to_real_file(self): |
| self._create_test_file('f', 'aFile', 'some contents') |
| self._create_test_file('h', 'link_to_file', 'aFile') |
| self.assertAllOsBehaviorsMatch('link_to_file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_broken_sym_link(self): |
| self._create_test_file('l', 'broken_link', 'broken') |
| self._create_test_file('l', 'loop', '/a/loop') |
| self.assertAllOsBehaviorsMatch('broken_link') |
| |
| def test_file_in_a_folder(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('f', 'a/b/file', 'contents') |
| self.assertAllOsBehaviorsMatch('a/b/file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_absolute_sym_link_to_folder(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('f', 'a/b/file', 'contents') |
| self._create_test_file('l', 'a/link', '/a/b') |
| self.assertAllOsBehaviorsMatch('a/link/file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_link_to_folder_after_chdir(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('f', 'a/b/file', 'contents') |
| self._create_test_file('l', 'a/link', '/a/b') |
| |
| real_dir, fake_dir = self._paths('a/b') |
| os.chdir(real_dir) |
| self.fake_os.chdir(fake_dir) |
| self.assertAllOsBehaviorsMatch('file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_relative_sym_link_to_folder(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('f', 'a/b/file', 'contents') |
| self._create_test_file('l', 'a/link', 'b') |
| self.assertAllOsBehaviorsMatch('a/link/file') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_sym_link_to_parent(self): |
| # Soft links on HFS+ / OS X behave differently. |
| if os.uname()[0] != 'Darwin': |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('l', 'a/b/c', '..') |
| self.assertAllOsBehaviorsMatch('a/b/c') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_path_through_sym_link_to_parent(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('f', 'a/target', 'contents') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('l', 'a/b/c', '..') |
| self.assertAllOsBehaviorsMatch('a/b/c/target') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_sym_link_to_sibling_directory(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self._create_test_file('l', 'a/b/c', '../sibling_of_b') |
| self.assertAllOsBehaviorsMatch('a/b/c/target') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_sym_link_to_sibling_directory_non_existant_file(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self._create_test_file('l', 'a/b/c', '../sibling_of_b') |
| self.assertAllOsBehaviorsMatch('a/b/c/file_does_not_exist') |
| |
| @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows') |
| def test_broken_sym_link_to_sibling_directory(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self._create_test_file('l', 'a/b/c', '../broken_sibling_of_b') |
| self.assertAllOsBehaviorsMatch('a/b/c/target') |
| |
| def test_relative_path(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self.assertAllOsBehaviorsMatch('a/b/../sibling_of_b/target') |
| |
| def test_broken_relative_path(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self.assertAllOsBehaviorsMatch('a/b/../broken/target') |
| |
| def test_bad_relative_path(self): |
| self._create_test_file('d', 'a') |
| self._create_test_file('f', 'a/target', 'contents') |
| self._create_test_file('d', 'a/b') |
| self._create_test_file('d', 'a/sibling_of_b') |
| self._create_test_file('f', 'a/sibling_of_b/target', 'contents') |
| self.assertAllOsBehaviorsMatch('a/b/../broken/../target') |
| |
| def test_getmtime_nonexistant_path(self): |
| self.assertOsPathMethodBehaviorMatches('getmtime', 'no/such/path') |
| |
| def test_builtin_open_modes(self): |
| self._create_test_file('f', 'read', 'some contents') |
| self._create_test_file('f', 'write', 'some contents') |
| self._create_test_file('f', 'append', 'some contents') |
| self.assertFileHandleBehaviorsMatch('read', 'r', 'other contents') |
| self.assertFileHandleBehaviorsMatch('write', 'w', 'other contents') |
| self.assertFileHandleBehaviorsMatch('append', 'a', 'other contents') |
| self._create_test_file('f', 'readplus', 'some contents') |
| self._create_test_file('f', 'writeplus', 'some contents') |
| self.assertFileHandleBehaviorsMatch( |
| 'readplus', 'r+', 'other contents') |
| self.assertFileHandleBehaviorsMatch( |
| 'writeplus', 'w+', 'other contents') |
| self._create_test_file('b', 'binaryread', b'some contents') |
| self._create_test_file('b', 'binarywrite', b'some contents') |
| self._create_test_file('b', 'binaryappend', b'some contents') |
| self.assertFileHandleBehaviorsMatch( |
| 'binaryread', 'rb', b'other contents') |
| self.assertFileHandleBehaviorsMatch( |
| 'binarywrite', 'wb', b'other contents') |
| self.assertFileHandleBehaviorsMatch( |
| 'binaryappend', 'ab', b'other contents') |
| self.assertFileHandleBehaviorsMatch('read', 'rb', 'other contents') |
| self.assertFileHandleBehaviorsMatch('write', 'wb', 'other contents') |
| self.assertFileHandleBehaviorsMatch('append', 'ab', 'other contents') |
| |
| # binary cannot have encoding |
| self.assertFileHandleOpenBehaviorsMatch('read', 'rb', encoding='enc') |
| self.assertFileHandleOpenBehaviorsMatch( |
| 'write', mode='wb', encoding='enc') |
| self.assertFileHandleOpenBehaviorsMatch('append', 'ab', encoding='enc') |
| |
| # text can have encoding |
| self.assertFileHandleOpenBehaviorsMatch('read', 'r', encoding='utf-8') |
| self.assertFileHandleOpenBehaviorsMatch('write', 'w', encoding='utf-8') |
| self.assertFileHandleOpenBehaviorsMatch( |
| 'append', 'a', encoding='utf-8') |
| |
| |
| def main(_): |
| unittest.main() |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |