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