Skip to content

Commit

Permalink
Added methods to access real files
Browse files Browse the repository at this point in the history
- allow to add really existing files and directory trees to the fake
file system, with the contents read on demand
- see #170
  • Loading branch information
mrbean-bremen committed Apr 14, 2017
1 parent f6fc906 commit 143438c
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 30 deletions.
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ The release versions are PyPi releases.
## Version 3.2 (as yet unreleased)

#### New Features
* Added the CHANGES.md release notes to the release manifest
* Added new methods to `fake_filesystem.FakeFilesystem` that make real files
and directories appear within the fake file system:
`add_real_file()`, `add_real_directory()` and `add_real_paths()`.
File contents are read from the real file system only when needed.
* Added the CHANGES.md release notes to the release manifest

#### Fixes
* `pathlib.glob()` incorrectly handled case under MacOS (#167)
Expand Down
7 changes: 6 additions & 1 deletion example.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,10 @@ def rm_tree(path):
shutil.rmtree(path)

def scandir(path):
"""Returns a list of directory entries for the given path."""
"""Return a list of directory entries for the given path."""
return list(os.scandir(path))

def file_contents(path):
"""Return the contents of the given path as byte array."""
with open(path, 'rb') as f:
return f.read()
13 changes: 12 additions & 1 deletion example_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import os
import sys

from pyfakefs.fake_filesystem_unittest import REAL_OPEN

if sys.version_info < (2, 7):
import unittest2 as unittest
else:
Expand Down Expand Up @@ -135,13 +137,22 @@ def test_scandir(self):
self.fs.CreateFile('/linktest/linked')
self.fs.CreateLink('/test/linked_file', '/linktest/linked')

entries = sorted(os.scandir('/test'), key=lambda e: e.name)
entries = sorted(example.scandir('/test'), key=lambda e: e.name)
self.assertEqual(3, len(entries))
self.assertEqual('linked_file', entries[1].name)
self.assertTrue(entries[0].is_dir())
self.assertTrue(entries[1].is_symlink())
self.assertTrue(entries[2].is_file())

def test_real_file_access(self):
"""Test `example.file_contents()` for a real file after adding it using `add_real_file()`."""
real_file = __file__
with REAL_OPEN(real_file, 'rb') as f:
real_contents = f.read()
self.assertRaises(IOError, example.file_contents, real_file)
self.fs.add_real_file(real_file)
self.assertEqual(example.file_contents(real_file), real_contents)


if __name__ == "__main__":
unittest.main()
133 changes: 132 additions & 1 deletion fake_filesystem_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4186,6 +4186,7 @@ def testDiskUsageOnFileCreation(self):

total_size = 100
self.filesystem.AddMountPoint('mount', total_size)

def create_too_large_file():
with fake_open('!mount!file', 'w') as dest:
dest.write('a' * (total_size + 1))
Expand All @@ -4199,7 +4200,6 @@ def create_too_large_file():

self.assertEqual(total_size, self.filesystem.GetDiskUsage('!mount').used)


def testFileSystemSizeAfterLargeFileCreation(self):
filesystem = fake_filesystem.FakeFilesystem(path_separator='!',
total_size=1024 * 1024 * 1024 * 100)
Expand Down Expand Up @@ -4444,5 +4444,136 @@ def testThatUncPathsAreAutoMounted(self):
self.assertEqual(5, self.filesystem.GetObject('!!foo!bar!bip!bop').st_dev)


class RealFileSystemAccessTest(TestCase):
def setUp(self):
# use the real path separator to work with the real file system
self.filesystem = fake_filesystem.FakeFilesystem()
self.fake_open = fake_filesystem.FakeFileOpen(self.filesystem)

def testAddNonExistingRealFileRaises(self):
nonexisting_path = os.path.join('nonexisting', 'test.txt')
self.assertRaises(OSError, self.filesystem.add_real_file, nonexisting_path)
self.assertFalse(self.filesystem.Exists(nonexisting_path))

def testAddNonExistingRealDirectoryRaises(self):
nonexisting_path = '/nonexisting'
self.assertRaisesIOError(errno.ENOENT, self.filesystem.add_real_directory, nonexisting_path)
self.assertFalse(self.filesystem.Exists(nonexisting_path))

def testExistingFakeFileRaises(self):
real_file_path = __file__
self.filesystem.CreateFile(real_file_path)
self.assertRaisesIOError(errno.EEXIST, self.filesystem.add_real_file, real_file_path)

def testExistingFakeDirectoryRaises(self):
real_dir_path = os.path.dirname(__file__)
self.filesystem.CreateDirectory(real_dir_path)
self.assertRaisesOSError(errno.EEXIST, self.filesystem.add_real_directory, real_dir_path)

def checkFakeFileStat(self, fake_file, real_file_path):
self.assertTrue(self.filesystem.Exists(real_file_path))
real_stat = os.stat(real_file_path)
self.assertIsNone(fake_file._byte_contents)
self.assertEqual(fake_file.st_size, real_stat.st_size)
self.assertEqual(fake_file.st_ctime, real_stat.st_ctime)
self.assertEqual(fake_file.st_atime, real_stat.st_atime)
self.assertEqual(fake_file.st_mtime, real_stat.st_mtime)
self.assertEqual(fake_file.st_uid, real_stat.st_uid)
self.assertEqual(fake_file.st_gid, real_stat.st_gid)

def checkReadOnlyFile(self, fake_file, real_file_path):
with open(real_file_path, 'rb') as f:
real_contents = f.read()
self.assertEqual(fake_file.byte_contents, real_contents)
self.assertRaisesIOError(errno.EACCES, self.fake_open, real_file_path, 'w')

def checkWritableFile(self, fake_file, real_file_path):
with open(real_file_path, 'rb') as f:
real_contents = f.read()
self.assertEqual(fake_file.byte_contents, real_contents)
with self.fake_open(real_file_path, 'wb') as f:
f.write(b'test')
with open(real_file_path, 'rb') as f:
real_contents1 = f.read()
self.assertEqual(real_contents1, real_contents)
with self.fake_open(real_file_path, 'rb') as f:
fake_contents = f.read()
self.assertEqual(fake_contents, b'test')

def testAddExistingRealFileReadOnly(self):
real_file_path = __file__
fake_file = self.filesystem.add_real_file(real_file_path)
self.checkFakeFileStat(fake_file, real_file_path)
self.assertEqual(fake_file.st_mode & 0o333, 0)
self.checkReadOnlyFile(fake_file, real_file_path)

def testAddExistingRealFileReadWrite(self):
real_file_path = os.path.realpath(__file__)
fake_file = self.filesystem.add_real_file(real_file_path, read_only=False)

self.checkFakeFileStat(fake_file, real_file_path)
self.assertEqual(fake_file.st_mode, os.stat(real_file_path).st_mode)
self.checkWritableFile(fake_file, real_file_path)

def testAddExistingRealDirectoryReadOnly(self):
real_dir_path = os.path.join(os.path.dirname(__file__), 'pyfakefs')
fake_dir = self.filesystem.add_real_directory(real_dir_path)
self.assertTrue(self.filesystem.Exists(real_dir_path))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'fake_filesystem.py')))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'fake_pathlib.py')))

file_path = os.path.join(real_dir_path, 'fake_tempfile.py')
fake_file = self.filesystem.ResolveObject(file_path)
self.checkFakeFileStat(fake_file, file_path)
self.checkReadOnlyFile(fake_file, file_path)

def testAddExistingRealDirectoryTree(self):
real_dir_path = os.path.dirname(__file__)
self.filesystem.add_real_directory(real_dir_path)
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'fake_filesystem_test.py')))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'pyfakefs', 'fake_filesystem.py')))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'pyfakefs', '__init__.py')))

def testAddExistingRealDirectoryReadWrite(self):
real_dir_path = os.path.join(os.path.dirname(__file__), 'pyfakefs')
self.filesystem.add_real_directory(real_dir_path, read_only=False)
self.assertTrue(self.filesystem.Exists(real_dir_path))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'fake_filesystem.py')))
self.assertTrue(self.filesystem.Exists(os.path.join(real_dir_path, 'fake_pathlib.py')))

file_path = os.path.join(real_dir_path, 'pytest_plugin.py')
fake_file = self.filesystem.ResolveObject(file_path)
self.checkFakeFileStat(fake_file, file_path)
self.checkWritableFile(fake_file, file_path)

def testAddExistingRealPathsReadOnly(self):
real_file_path = os.path.realpath(__file__)
real_dir_path = os.path.join(os.path.dirname(__file__), 'pyfakefs')
self.filesystem.add_real_paths([real_file_path, real_dir_path])

fake_file = self.filesystem.ResolveObject(real_file_path)
self.checkFakeFileStat(fake_file, real_file_path)
self.checkReadOnlyFile(fake_file, real_file_path)

real_file_path = os.path.join(real_dir_path, 'fake_filesystem_shutil.py')
fake_file = self.filesystem.ResolveObject(real_file_path)
self.checkFakeFileStat(fake_file, real_file_path)
self.checkReadOnlyFile(fake_file, real_file_path)

def testAddExistingRealPathsReadWrite(self):
real_file_path = os.path.realpath(__file__)
real_dir_path = os.path.join(os.path.dirname(__file__), 'pyfakefs')
self.filesystem.add_real_paths([real_file_path, real_dir_path], read_only=False)

fake_file = self.filesystem.ResolveObject(real_file_path)
self.checkFakeFileStat(fake_file, real_file_path)
self.checkWritableFile(fake_file, real_file_path)

real_file_path = os.path.join(real_dir_path, 'fake_filesystem_glob.py')
fake_file = self.filesystem.ResolveObject(real_file_path)
self.checkFakeFileStat(fake_file, real_file_path)
self.checkWritableFile(fake_file, real_file_path)


if __name__ == '__main__':
unittest.main()
24 changes: 23 additions & 1 deletion fake_filesystem_unittest_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def test_own_path_module(self):


@unittest.skipIf(sys.version_info < (2, 7), "No byte strings in Python 2.6")
class TestCopyRealFile(TestPyfakefsUnittestBase):
class TestCopyOrAddRealFile(TestPyfakefsUnittestBase):
"""Tests the `fake_filesystem_unittest.TestCase.copyRealFile()` method."""
with open(__file__) as f:
real_string_contents = f.read()
Expand Down Expand Up @@ -235,6 +235,28 @@ def testCopyRealFileNoDestination(self):
self.copyRealFile(real_file_path)
self.assertTrue(self.fs.Exists(real_file_path))

def testAddRealFile(self):
'''Add a real file to the fake file system to be read on demand'''

# this tests only the basic functionality inside a unit test, more thorough tests
# are done in fake_filesystem_test.RealFileSystemAccessTest
real_file_path = __file__
fake_file = self.fs.add_real_file(real_file_path)
self.assertTrue(self.fs.Exists(real_file_path))
self.assertIsNone(fake_file._byte_contents)
self.assertEqual(self.real_byte_contents, fake_file.byte_contents)

def testAddRealDirectory(self):
'''Add a real directory and the contained files to the fake file system to be read on demand'''

# this tests only the basic functionality inside a unit test, more thorough tests
# are done in fake_filesystem_test.RealFileSystemAccessTest
# Note: this test fails (add_real_directory raises) if 'genericpath' is not added to SKIPNAMES
real_dir_path = os.path.join(os.path.dirname(__file__), 'pyfakefs')
self.fs.add_real_directory(real_dir_path)
self.assertTrue(self.fs.Exists(real_dir_path))
self.assertTrue(self.fs.Exists(os.path.join(real_dir_path, 'fake_filesystem.py')))


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

0 comments on commit 143438c

Please sign in to comment.