Mercurial > piecrust2
comparison tests/mockutil.py @ 35:e4c345dcf33c
More unit tests, fix a bug with the skip patterns.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 20 Aug 2014 21:46:27 -0700 |
parents | 43091c9837bf |
children | 485682a6de50 |
comparison
equal
deleted
inserted
replaced
34:bdb103c57168 | 35:e4c345dcf33c |
---|---|
1 import io | 1 import io |
2 import time | 2 import time |
3 import random | 3 import random |
4 import codecs | 4 import codecs |
5 import shutil | |
5 import os.path | 6 import os.path |
6 import functools | 7 import functools |
7 import mock | 8 import mock |
8 import yaml | 9 import yaml |
9 from piecrust.app import PieCrust, PieCrustConfiguration | 10 from piecrust.app import PieCrust, PieCrustConfiguration |
49 root_dir = self.path('/kitchen') | 50 root_dir = self.path('/kitchen') |
50 return PieCrust(root_dir, cache=False) | 51 return PieCrust(root_dir, cache=False) |
51 | 52 |
52 def withDir(self, path): | 53 def withDir(self, path): |
53 path = path.replace('\\', '/') | 54 path = path.replace('\\', '/') |
54 cur = self._fs[self._root] | 55 path = path.lstrip('/') |
55 for b in path.split('/'): | 56 path = '/%s/%s' % (self._root, path) |
56 if b not in cur: | 57 self._createDir(path) |
57 cur[b] = {} | |
58 cur = cur[b] | |
59 return self | 58 return self |
60 | 59 |
61 def withFile(self, path, contents): | 60 def withFile(self, path, contents): |
62 path = path.replace('\\', '/') | 61 path = path.replace('\\', '/') |
63 cur = self._fs[self._root] | 62 path = path.lstrip('/') |
64 bits = path.split('/') | 63 path = '/%s/%s' % (self._root, path) |
65 for b in bits[:-1]: | 64 self._createFile(path, contents) |
66 if b not in cur: | |
67 cur[b] = {} | |
68 cur = cur[b] | |
69 cur[bits[-1]] = (contents, {'mtime': time.time()}) | |
70 return self | 65 return self |
71 | 66 |
72 def withAsset(self, path, contents): | 67 def withAsset(self, path, contents): |
73 return self.withFile('kitchen/' + path, contents) | 68 return self.withFile('kitchen/' + path, contents) |
74 | 69 |
104 url_base, ext = os.path.splitext(page_url) | 99 url_base, ext = os.path.splitext(page_url) |
105 dirname = url_base + '-assets' | 100 dirname = url_base + '-assets' |
106 return self.withAsset('_content/%s/%s' % (dirname, name), | 101 return self.withAsset('_content/%s/%s' % (dirname, name), |
107 contents) | 102 contents) |
108 | 103 |
109 | 104 def getStructure(self, path=None): |
110 class mock_fs_scope(object): | 105 root = self._fs[self._root] |
111 def __init__(self, fs): | 106 if path: |
112 self._fs = fs | 107 root = self._getEntry(self.path(path)) |
113 self._root = None | 108 |
114 self._patchers = [] | 109 res = {} |
115 self._originals = {} | 110 for k, v in root.items(): |
116 if isinstance(fs, mock_fs): | 111 self._getStructureRecursive(v, res, k) |
117 self._fs = fs._fs | 112 return res |
118 self._root = fs._root | 113 |
119 | 114 def _getStructureRecursive(self, src, target, name): |
120 def __enter__(self): | 115 if isinstance(src, tuple): |
121 self._startMock() | 116 target[name] = src[0] |
122 return self | 117 return |
123 | 118 |
124 def __exit__(self, type, value, traceback): | 119 e = {} |
125 self._endMock() | 120 for k, v in src.items(): |
126 | 121 self._getStructureRecursive(v, e, k) |
127 def _startMock(self): | 122 target[name] = e |
128 self._createMock('__main__.open', open, self._open, create=True) | 123 |
129 self._createMock('codecs.open', codecs.open, self._codecsOpen) | 124 def _getEntry(self, path): |
130 self._createMock('os.listdir', os.listdir, self._listdir) | |
131 self._createMock('os.path.isdir', os.path.isdir, self._isdir) | |
132 self._createMock('os.path.isfile', os.path.isfile, self._isfile) | |
133 self._createMock('os.path.islink', os.path.islink, self._islink) | |
134 self._createMock('os.path.getmtime', os.path.getmtime, self._getmtime) | |
135 for p in self._patchers: | |
136 p.start() | |
137 | |
138 def _endMock(self): | |
139 for p in self._patchers: | |
140 p.stop() | |
141 | |
142 def _createMock(self, name, orig, func, **kwargs): | |
143 self._originals[name] = orig | |
144 self._patchers.append(mock.patch(name, func, **kwargs)) | |
145 | |
146 def _open(self, path, *args, **kwargs): | |
147 path = os.path.normpath(path) | |
148 if path.startswith(resources_path): | |
149 return self._originals['__main__.open'](path, **kwargs) | |
150 e = self._getFsEntry(path) | |
151 if e is None: | |
152 raise OSError("No such file: %s" % path) | |
153 if not isinstance(e, tuple): | |
154 raise OSError("'%s' is not a file" % path) | |
155 return io.StringIO(e[0]) | |
156 | |
157 def _codecsOpen(self, path, *args, **kwargs): | |
158 path = os.path.normpath(path) | |
159 if path.startswith(resources_path): | |
160 return self._originals['codecs.open'](path, *args, **kwargs) | |
161 e = self._getFsEntry(path) | |
162 if e is None: | |
163 raise OSError("No such file: %s" % path) | |
164 if not isinstance(e, tuple): | |
165 raise OSError("'%s' is not a file" % path) | |
166 return io.StringIO(e[0]) | |
167 | |
168 def _listdir(self, path): | |
169 if not path.startswith('/' + self._root): | |
170 return self._originals['os.listdir'](path) | |
171 e = self._getFsEntry(path) | |
172 if e is None: | |
173 raise OSError("No such directory: %s" % path) | |
174 if not isinstance(e, dict): | |
175 raise OSError("'%s' is not a directory." % path) | |
176 return list(e.keys()) | |
177 | |
178 def _isdir(self, path): | |
179 if not path.startswith('/' + self._root): | |
180 return self._originals['os.path.isdir'](path) | |
181 e = self._getFsEntry(path) | |
182 return e is not None and isinstance(e, dict) | |
183 | |
184 def _isfile(self, path): | |
185 if not path.startswith('/' + self._root): | |
186 return self._originals['os.path.isfile'](path) | |
187 e = self._getFsEntry(path) | |
188 return e is not None and isinstance(e, tuple) | |
189 | |
190 def _islink(self, path): | |
191 if not path.startswith('/' + self._root): | |
192 return self._originals['os.path.islink'](path) | |
193 return False | |
194 | |
195 def _getmtime(self, path): | |
196 if not path.startswith('/' + self._root): | |
197 return self._originals['os.path.getmtime'](path) | |
198 e = self._getFsEntry(path) | |
199 if e is None: | |
200 raise OSError("No such file: %s" % path) | |
201 return e[1]['mtime'] | |
202 | |
203 def _getFsEntry(self, path): | |
204 cur = self._fs | 125 cur = self._fs |
205 path = path.replace('\\', '/').lstrip('/') | 126 path = path.replace('\\', '/').lstrip('/') |
206 bits = path.split('/') | 127 bits = path.split('/') |
207 for p in bits: | 128 for p in bits: |
208 try: | 129 try: |
209 cur = cur[p] | 130 cur = cur[p] |
210 except KeyError: | 131 except KeyError: |
211 return None | 132 return None |
212 return cur | 133 return cur |
213 | 134 |
135 def _createDir(self, path): | |
136 cur = self._fs | |
137 bits = path.strip('/').split('/') | |
138 for b in bits: | |
139 if b not in cur: | |
140 cur[b] = {} | |
141 cur = cur[b] | |
142 return self | |
143 | |
144 def _createFile(self, path, contents): | |
145 cur = self._fs | |
146 bits = path.strip('/').split('/') | |
147 for b in bits[:-1]: | |
148 if b not in cur: | |
149 cur[b] = {} | |
150 cur = cur[b] | |
151 cur[bits[-1]] = (contents, {'mtime': time.time()}) | |
152 return self | |
153 | |
154 | |
155 class mock_fs_scope(object): | |
156 def __init__(self, fs): | |
157 self._fs = fs | |
158 self._patchers = [] | |
159 self._originals = {} | |
160 | |
161 @property | |
162 def root(self): | |
163 return self._fs._root | |
164 | |
165 def __enter__(self): | |
166 self._startMock() | |
167 return self | |
168 | |
169 def __exit__(self, type, value, traceback): | |
170 self._endMock() | |
171 | |
172 def _startMock(self): | |
173 self._createMock('__main__.open', open, self._open, create=True) | |
174 self._createMock('codecs.open', codecs.open, self._codecsOpen) | |
175 self._createMock('os.listdir', os.listdir, self._listdir) | |
176 self._createMock('os.makedirs', os.makedirs, self._makedirs) | |
177 self._createMock('os.path.isdir', os.path.isdir, self._isdir) | |
178 self._createMock('os.path.isfile', os.path.isfile, self._isfile) | |
179 self._createMock('os.path.islink', os.path.islink, self._islink) | |
180 self._createMock('os.path.getmtime', os.path.getmtime, self._getmtime) | |
181 self._createMock('shutil.copyfile', shutil.copyfile, self._copyfile) | |
182 for p in self._patchers: | |
183 p.start() | |
184 | |
185 def _endMock(self): | |
186 for p in self._patchers: | |
187 p.stop() | |
188 | |
189 def _createMock(self, name, orig, func, **kwargs): | |
190 self._originals[name] = orig | |
191 self._patchers.append(mock.patch(name, func, **kwargs)) | |
192 | |
193 def _open(self, path, *args, **kwargs): | |
194 path = os.path.normpath(path) | |
195 if path.startswith(resources_path): | |
196 return self._originals['__main__.open'](path, **kwargs) | |
197 e = self._getFsEntry(path) | |
198 if e is None: | |
199 raise OSError("No such file: %s" % path) | |
200 if not isinstance(e, tuple): | |
201 raise OSError("'%s' is not a file" % path) | |
202 return io.StringIO(e[0]) | |
203 | |
204 def _codecsOpen(self, path, *args, **kwargs): | |
205 path = os.path.normpath(path) | |
206 if path.startswith(resources_path): | |
207 return self._originals['codecs.open'](path, *args, **kwargs) | |
208 e = self._getFsEntry(path) | |
209 if e is None: | |
210 raise OSError("No such file: %s" % path) | |
211 if not isinstance(e, tuple): | |
212 raise OSError("'%s' is not a file" % path) | |
213 return io.StringIO(e[0]) | |
214 | |
215 def _listdir(self, path): | |
216 if not path.startswith('/' + self.root): | |
217 return self._originals['os.listdir'](path) | |
218 e = self._getFsEntry(path) | |
219 if e is None: | |
220 raise OSError("No such directory: %s" % path) | |
221 if not isinstance(e, dict): | |
222 raise OSError("'%s' is not a directory." % path) | |
223 return list(e.keys()) | |
224 | |
225 def _makedirs(self, path, mode): | |
226 if not path.startswith('/' + self.root): | |
227 raise Exception("Shouldn't create directory: %s" % path) | |
228 self._fs._createDir(path) | |
229 | |
230 def _isdir(self, path): | |
231 if not path.startswith('/' + self.root): | |
232 return self._originals['os.path.isdir'](path) | |
233 e = self._getFsEntry(path) | |
234 return e is not None and isinstance(e, dict) | |
235 | |
236 def _isfile(self, path): | |
237 if not path.startswith('/' + self.root): | |
238 return self._originals['os.path.isfile'](path) | |
239 e = self._getFsEntry(path) | |
240 return e is not None and isinstance(e, tuple) | |
241 | |
242 def _islink(self, path): | |
243 if not path.startswith('/' + self.root): | |
244 return self._originals['os.path.islink'](path) | |
245 return False | |
246 | |
247 def _getmtime(self, path): | |
248 if not path.startswith('/' + self.root): | |
249 return self._originals['os.path.getmtime'](path) | |
250 e = self._getFsEntry(path) | |
251 if e is None: | |
252 raise OSError("No such file: %s" % path) | |
253 return e[1]['mtime'] | |
254 | |
255 def _copyfile(self, src, dst): | |
256 if not src.startswith('/' + self.root): | |
257 with open(src, 'r') as fp: | |
258 src_text = fp.read() | |
259 else: | |
260 e = self._getFsEntry(src) | |
261 src_text = e[0] | |
262 if not dst.startswith('/' + self.root): | |
263 raise Exception("Shouldn't copy to: %s" % dst) | |
264 self._fs._createFile(dst, src_text) | |
265 | |
266 def _getFsEntry(self, path): | |
267 return self._fs._getEntry(path) | |
268 |