OLD | NEW |
1 # Copyright 2014 Altera Corporation. All Rights Reserved. | 1 # Copyright 2014 Altera Corporation. All Rights Reserved. |
2 # Author: John McGehee | 2 # Copyright 2015 John McGehee |
3 # | |
4 # Copyright 2014 John McGehee. All Rights Reserved. | |
5 # | 3 # |
6 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
7 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
8 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
9 # | 7 # |
10 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
11 # | 9 # |
12 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
13 # distributed under the License is distributed on an "AS IS" BASIS, | 11 # distributed under the License is distributed on an "AS IS" BASIS, |
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
(...skipping 14 matching lines...) Expand all Loading... |
29 | 27 |
30 It is expected that `setUp()` be invoked at the beginning of the derived | 28 It is expected that `setUp()` be invoked at the beginning of the derived |
31 class' `setUp()` method, and `tearDownPyfakefs()` be invoked at the end of the | 29 class' `setUp()` method, and `tearDownPyfakefs()` be invoked at the end of the |
32 derived class' `tearDown()` method. | 30 derived class' `tearDown()` method. |
33 | 31 |
34 During the test, everything uses the fake file system and modules. This means | 32 During the test, everything uses the fake file system and modules. This means |
35 that even in your test, you can use familiar functions like `open()` and | 33 that even in your test, you can use familiar functions like `open()` and |
36 `os.makedirs()` to manipulate the fake file system. | 34 `os.makedirs()` to manipulate the fake file system. |
37 | 35 |
38 This also means existing unit tests that use the real file system can be | 36 This also means existing unit tests that use the real file system can be |
39 retro-fitted to use `pyfakefs` by simply changing their base class from | 37 retrofitted to use `pyfakefs` by simply changing their base class from |
40 `:py:class`unittest.TestCase` to | 38 `:py:class`unittest.TestCase` to |
41 `:py:class`pyfakefs.fake_filesystem_unittest.TestCase`. | 39 `:py:class`pyfakefs.fake_filesystem_unittest.TestCase`. |
42 """ | 40 """ |
43 | 41 |
44 import sys | 42 import sys |
45 import unittest | 43 import unittest |
46 import doctest | 44 import doctest |
47 import inspect | |
48 import fake_filesystem | 45 import fake_filesystem |
49 import fake_filesystem_glob | 46 import fake_filesystem_glob |
50 import fake_filesystem_shutil | 47 import fake_filesystem_shutil |
51 import fake_tempfile | 48 import fake_tempfile |
| 49 if sys.version_info < (3,): |
| 50 import __builtin__ as builtins |
| 51 else: |
| 52 import builtins |
52 | 53 |
53 import mock | 54 import mox3.stubout |
54 | 55 |
55 def load_doctests(loader, tests, ignore, module): | 56 def load_doctests(loader, tests, ignore, module): |
56 '''Load the doctest tests for the specified module into unittest.''' | 57 '''Load the doctest tests for the specified module into unittest.''' |
57 _patcher = _Patcher() | 58 _patcher = Patcher() |
58 globs = _patcher.replaceGlobs(vars(module)) | 59 globs = _patcher.replaceGlobs(vars(module)) |
59 tests.addTests(doctest.DocTestSuite(module, | 60 tests.addTests(doctest.DocTestSuite(module, |
60 globs=globs, | 61 globs=globs, |
61 setUp=_patcher.setUp, | 62 setUp=_patcher.setUp, |
62 tearDown=_patcher.tearDown)) | 63 tearDown=_patcher.tearDown)) |
63 return tests | 64 return tests |
64 | 65 |
65 | 66 |
66 class TestCase(unittest.TestCase): | 67 class TestCase(unittest.TestCase): |
67 def __init__(self, methodName='runTest'): | 68 def __init__(self, methodName='runTest'): |
68 super(TestCase, self).__init__(methodName) | 69 super(TestCase, self).__init__(methodName) |
69 self._stubber = _Patcher() | 70 self._stubber = Patcher() |
70 | 71 |
71 @property | 72 @property |
72 def fs(self): | 73 def fs(self): |
73 return self._stubber.fs | 74 return self._stubber.fs |
74 | 75 |
75 @property | 76 @property |
76 def patches(self): | 77 def patches(self): |
77 return self._stubber.patches | 78 return self._stubber.patches |
78 | 79 |
79 def setUpPyfakefs(self): | 80 def setUpPyfakefs(self): |
80 '''Bind the file-related modules to the :py:class:`pyfakefs` fake file | 81 '''Bind the file-related modules to the :py:class:`pyfakefs` fake file |
81 system instead of the real file system. Also bind the fake `file()` and | 82 system instead of the real file system. Also bind the fake `file()` and |
82 `open()` functions. | 83 `open()` functions. |
83 | 84 |
84 Invoke this at the beginning of the `setUp()` method in your unit test | 85 Invoke this at the beginning of the `setUp()` method in your unit test |
85 class. | 86 class. |
86 ''' | 87 ''' |
87 self._stubber.setUp() | 88 self._stubber.setUp() |
88 self.addCleanup(self._stubber.tearDown) | 89 self.addCleanup(self._stubber.tearDown) |
89 | 90 |
90 | 91 |
91 def tearDownPyfakefs(self): | 92 def tearDownPyfakefs(self): |
92 ''':meth:`pyfakefs.fake_filesystem_unittest.setUpPyfakefs` registers the | 93 ''':meth:`pyfakefs.fake_filesystem_unittest.setUpPyfakefs` registers the |
93 tear down procedure using :meth:unittest.TestCase.addCleanup`. Thus thi
s | 94 tear down procedure using :meth:`unittest.TestCase.addCleanup`. Thus th
is |
94 method is deprecated, and remains just for backward compatibility. | 95 method is deprecated, and remains just for backward compatibility. |
95 ''' | 96 ''' |
96 pass | 97 pass |
97 | 98 |
98 class _Patcher(object): | 99 class Patcher(object): |
99 ''' | 100 ''' |
100 Instantiate a stub creator to bind and un-bind the file-related modules to | 101 Instantiate a stub creator to bind and un-bind the file-related modules to |
101 the :py:module:`pyfakefs` fake modules. | 102 the :py:mod:`pyfakefs` fake modules. |
102 ''' | 103 ''' |
103 SKIPMODULES = set([None, fake_filesystem, fake_filesystem_glob, | 104 SKIPMODULES = set([None, fake_filesystem, fake_filesystem_glob, |
104 fake_filesystem_shutil, fake_tempfile, unittest, | 105 fake_filesystem_shutil, fake_tempfile, sys]) |
105 sys]) | |
106 '''Stub nothing that is imported within these modules. | 106 '''Stub nothing that is imported within these modules. |
107 `sys` is included to prevent `sys.path` from being stubbed with the fake | 107 `sys` is included to prevent `sys.path` from being stubbed with the fake |
108 `os.path`. | 108 `os.path`. |
109 ''' | 109 ''' |
110 assert None in SKIPMODULES, "sys.modules contains 'None' values; must skip t
hem." | 110 assert None in SKIPMODULES, "sys.modules contains 'None' values; must skip t
hem." |
111 | 111 |
112 SKIPNAMES = set(['os', 'glob', 'path', 'shutil', 'tempfile']) | 112 SKIPNAMES = set(['os', 'glob', 'path', 'shutil', 'tempfile']) |
113 | 113 |
114 def __init__(self): | 114 def __init__(self): |
115 # Attributes set by _findModules() | 115 # Attributes set by _findModules() |
116 self._osModuleNames = None | 116 self._osModules = None |
117 self._globModuleNames = None | 117 self._globModules = None |
118 self._pathModuleNames = None | 118 self._pathModules = None |
119 self._shutilModuleNames = None | 119 self._shutilModules = None |
120 self._tempfileModuleNames = None | 120 self._tempfileModules = None |
121 self._findModules() | 121 self._findModules() |
122 assert None not in vars(self).values(), \ | 122 assert None not in vars(self).values(), \ |
123 "_findModules() missed the initialization of an instance variabl
e" | 123 "_findModules() missed the initialization of an instance variabl
e" |
124 | 124 |
125 # Attributes set by _refresh() | 125 # Attributes set by _refresh() |
| 126 self._stubs = None |
126 self.fs = None | 127 self.fs = None |
127 self.fake_os = None | 128 self.fake_os = None |
128 self.fake_glob = None | 129 self.fake_glob = None |
129 self.fake_path = None | 130 self.fake_path = None |
130 self.fake_shutil = None | 131 self.fake_shutil = None |
131 self.fake_tempfile_ = None | 132 self.fake_tempfile_ = None |
132 self.fake_open = None | 133 self.fake_open = None |
133 # _isStale is set by tearDown(), reset by _refresh() | 134 # _isStale is set by tearDown(), reset by _refresh() |
134 self._isStale = True | 135 self._isStale = True |
135 self._refresh() | 136 self._refresh() |
136 assert None not in vars(self).values(), \ | 137 assert None not in vars(self).values(), \ |
137 "_refresh() missed the initialization of an instance variable" | 138 "_refresh() missed the initialization of an instance variable" |
138 assert self._isStale == False, "_refresh() did not reset _isStale" | 139 assert self._isStale == False, "_refresh() did not reset _isStale" |
139 | 140 |
140 def _findModules(self): | 141 def _findModules(self): |
141 '''Find and cache all modules that import file system modules. | 142 '''Find and cache all modules that import file system modules. |
142 Later, `setUp()` will stub these with the fake file system | 143 Later, `setUp()` will stub these with the fake file system |
143 modules. | 144 modules. |
144 ''' | 145 ''' |
145 self._osModuleNames = set() | 146 self._osModules = set() |
146 self._globModuleNames = set() | 147 self._globModules = set() |
147 self._pathModuleNames = set() | 148 self._pathModules = set() |
148 self._shutilModuleNames = set() | 149 self._shutilModules = set() |
149 self._tempfileModuleNames = set() | 150 self._tempfileModules = set() |
150 for name, module in set(sys.modules.items()): | 151 for name, module in set(sys.modules.items()): |
151 if module in self.SKIPMODULES or name in self.SKIPNAMES or (not insp
ect.ismodule(module)): | 152 if module in self.SKIPMODULES or name in self.SKIPNAMES: |
152 continue | 153 continue |
153 if 'os' in module.__dict__ and inspect.ismodule(module.__dict__['os'
]): | 154 if 'os' in module.__dict__: |
154 self._osModuleNames.add(name + '.os') | 155 self._osModules.add(module) |
155 if 'glob' in module.__dict__: | 156 if 'glob' in module.__dict__: |
156 self._globModuleNames.add(name + '.glob') | 157 self._globModules.add(module) |
157 if 'path' in module.__dict__: | 158 if 'path' in module.__dict__: |
158 self._pathModuleNames.add(name + '.path') | 159 self._pathModules.add(module) |
159 if 'shutil' in module.__dict__: | 160 if 'shutil' in module.__dict__: |
160 self._shutilModuleNames.add(name + '.shutil') | 161 self._shutilModules.add(module) |
161 if 'tempfile' in module.__dict__: | 162 if 'tempfile' in module.__dict__: |
162 self._tempfileModuleNames.add(name + '.tempfile') | 163 self._tempfileModules.add(module) |
163 | 164 |
164 def _refresh(self): | 165 def _refresh(self): |
165 '''Renew the fake file system and set the _isStale flag to `False`.''' | 166 '''Renew the fake file system and set the _isStale flag to `False`.''' |
166 mock.patch.stopall() | 167 if self._stubs is not None: |
167 | 168 self._stubs.SmartUnsetAll() |
| 169 self._stubs = mox3.stubout.StubOutForTesting() |
| 170 |
168 self.fs = fake_filesystem.FakeFilesystem() | 171 self.fs = fake_filesystem.FakeFilesystem() |
169 self.fake_os = fake_filesystem.FakeOsModule(self.fs) | 172 self.fake_os = fake_filesystem.FakeOsModule(self.fs) |
170 self.fake_glob = fake_filesystem_glob.FakeGlobModule(self.fs) | 173 self.fake_glob = fake_filesystem_glob.FakeGlobModule(self.fs) |
171 self.fake_path = self.fake_os.path | 174 self.fake_path = self.fake_os.path |
172 self.fake_shutil = fake_filesystem_shutil.FakeShutilModule(self.fs) | 175 self.fake_shutil = fake_filesystem_shutil.FakeShutilModule(self.fs) |
173 self.fake_tempfile_ = fake_tempfile.FakeTempfileModule(self.fs) | 176 self.fake_tempfile_ = fake_tempfile.FakeTempfileModule(self.fs) |
174 self.fake_open = fake_filesystem.FakeFileOpen(self.fs) | 177 self.fake_open = fake_filesystem.FakeFileOpen(self.fs) |
175 | 178 |
176 self._isStale = False | 179 self._isStale = False |
177 | 180 |
178 def setUp(self, doctester=None): | 181 def setUp(self, doctester=None): |
179 '''Bind the file-related modules to the :py:module:`pyfakefs` fake | 182 '''Bind the file-related modules to the :py:mod:`pyfakefs` fake |
180 modules real ones. Also bind the fake `file()` and `open()` functions. | 183 modules real ones. Also bind the fake `file()` and `open()` functions. |
181 ''' | 184 ''' |
182 if self._isStale: | 185 if self._isStale: |
183 self._refresh() | 186 self._refresh() |
184 | 187 |
185 if doctester is not None: | 188 if doctester is not None: |
186 doctester.globs = self.replaceGlobs(doctester.globs) | 189 doctester.globs = self.replaceGlobs(doctester.globs) |
187 | 190 |
188 def startPatch(self, realModuleName, fakeModule): | 191 if sys.version_info < (3,): |
189 if realModuleName == 'unittest.main.os': | 192 # No file() in Python3 |
190 # Known issue with unittest.main resolving to unittest.main.Test
Program | 193 self._stubs.SmartSet(builtins, 'file', self.fake_open) |
191 # See mock module bug 250, https://code.google.com/p/mock/issues
/detail?id=250. | 194 self._stubs.SmartSet(builtins, 'open', self.fake_open) |
192 return | 195 |
193 patch = mock.patch(realModuleName, new=fakeModule) | 196 for module in self._osModules: |
194 try: | 197 self._stubs.SmartSet(module, 'os', self.fake_os) |
195 patch.start() | 198 for module in self._globModules: |
196 except: | 199 self._stubs.SmartSet(module, 'glob', self.fake_glob) |
197 target, attribute = realModuleName.rsplit('.', 1) | 200 for module in self._pathModules: |
198 print("Warning: Could not patch '{}' on module '{}' because '{}'
resolves to {}".format(attribute, target, target, patch.getter())) | 201 self._stubs.SmartSet(module, 'path', self.fake_path) |
199 print(" See mock module bug 250, https://code.google.com
/p/mock/issues/detail?id=250") | 202 for module in self._shutilModules: |
200 | 203 self._stubs.SmartSet(module, 'shutil', self.fake_shutil) |
201 startPatch(self, '__builtin__.file', self.fake_open) | 204 for module in self._tempfileModules: |
202 startPatch(self, '__builtin__.open', self.fake_open) | 205 self._stubs.SmartSet(module, 'tempfile', self.fake_tempfile_) |
203 | 206 |
204 for module in self._osModuleNames: | |
205 startPatch(self, module, self.fake_os) | |
206 for module in self._globModuleNames: | |
207 startPatch(self, module, self.fake_glob) | |
208 for module in self._pathModuleNames: | |
209 startPatch(self, module, self.fake_path) | |
210 for module in self._shutilModuleNames: | |
211 startPatch(self, module, self.fake_shutil) | |
212 for module in self._tempfileModuleNames: | |
213 startPatch(self, module, self.fake_tempfile_) | |
214 | |
215 def replaceGlobs(self, globs_): | 207 def replaceGlobs(self, globs_): |
216 globs = globs_.copy() | 208 globs = globs_.copy() |
217 if self._isStale: | 209 if self._isStale: |
218 self._refresh() | 210 self._refresh() |
219 if 'os' in globs: | 211 if 'os' in globs: |
220 globs['os'] = fake_filesystem.FakeOsModule(self.fs) | 212 globs['os'] = fake_filesystem.FakeOsModule(self.fs) |
221 if 'glob' in globs: | 213 if 'glob' in globs: |
222 globs['glob'] = fake_filesystem_glob.FakeGlobModule(self.fs) | 214 globs['glob'] = fake_filesystem_glob.FakeGlobModule(self.fs) |
223 if 'path' in globs: | 215 if 'path' in globs: |
224 fake_os = globs['os'] if 'os' in globs \ | 216 globs['path'] = fake_filesystem.FakePathModule(self.fs) |
225 else fake_filesystem.FakeOsModule(self.fs) | |
226 globs['path'] = fake_os.path | |
227 if 'shutil' in globs: | 217 if 'shutil' in globs: |
228 globs['shutil'] = fake_filesystem_shutil.FakeShutilModule(self.fs) | 218 globs['shutil'] = fake_filesystem_shutil.FakeShutilModule(self.fs) |
229 if 'tempfile' in globs: | 219 if 'tempfile' in globs: |
230 globs['tempfile'] = fake_tempfile.FakeTempfileModule(self.fs) | 220 globs['tempfile'] = fake_tempfile.FakeTempfileModule(self.fs) |
231 return globs | 221 return globs |
232 | 222 |
233 def tearDown(self, doctester=None): | 223 def tearDown(self, doctester=None): |
234 '''Clear the fake filesystem bindings created by `setUp()`.''' | 224 '''Clear the fake filesystem bindings created by `setUp()`.''' |
235 self._isStale = True | 225 self._isStale = True |
236 mock.patch.stopall() | 226 self._stubs.SmartUnsetAll() |
OLD | NEW |