Mercurial > wikked
comparison tests/mock.py @ 49:fb6ae96756c1
Added unit tests.
Refactored core APIs to make them more testable.
Removed unused stuff like caching the configuration in the SQL database.
Fixed the web bootstrap.
Some cosmetic changes to be PEP8 compliant.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Mon, 28 Jan 2013 23:13:04 -0800 |
parents | |
children | 2733871775cd |
comparison
equal
deleted
inserted
replaced
48:9658edea3121 | 49:fb6ae96756c1 |
---|---|
1 import re | |
2 import os.path | |
3 import types | |
4 import codecs | |
5 import logging | |
6 import StringIO | |
7 from wikked.page import Page | |
8 from wikked.fs import PageNotFoundError | |
9 from wikked.db import Database | |
10 from wikked.indexer import WikiIndex | |
11 from wikked.scm import SourceControl | |
12 | |
13 | |
14 class MockWikiParameters(object): | |
15 def __init__(self): | |
16 self.formatters = { | |
17 self._passthrough: ['txt', 'html'] | |
18 } | |
19 | |
20 self.config_text = "" | |
21 self.special_filenames = [] | |
22 | |
23 self.logger_factory = lambda: logging.getLogger('wikked.tests') | |
24 self.page_factory = lambda wiki, url: MockPage(wiki, url) | |
25 self.config_factory = lambda: StringIO.StringIO(self.config_text) | |
26 self.fs_factory = lambda cfg: MockFileSystem() | |
27 self.index_factory = lambda cfg: MockWikiIndex() | |
28 self.db_factory = lambda cfg: MockDatabase() | |
29 self.scm_factory = lambda cfg: MockSourceControl() | |
30 | |
31 def getSpecialFilenames(self): | |
32 return self.special_filenames | |
33 | |
34 def _passthrough(self, text): | |
35 return text | |
36 | |
37 | |
38 class MockPage(Page): | |
39 def __init__(self, wiki, url): | |
40 Page.__init__(self, wiki, url) | |
41 | |
42 | |
43 class MockDatabase(Database): | |
44 def __init__(self, content=None, logger=None): | |
45 Database.__init__(self, logger) | |
46 self.content = content | |
47 self._open_count = 0 | |
48 | |
49 def initDb(self): | |
50 pass | |
51 | |
52 def open(self): | |
53 self._open_count += 1 | |
54 | |
55 def close(self): | |
56 self._open_count -= 1 | |
57 if self._open_count < 0: | |
58 raise Exception( | |
59 "The database was closed more times than it was open.") | |
60 | |
61 def reset(self, pages): | |
62 pass | |
63 | |
64 def update(self, pages): | |
65 pass | |
66 | |
67 def getPageUrls(self, subdir=None): | |
68 return [] | |
69 | |
70 def getPages(self, subdir=None): | |
71 return [] | |
72 | |
73 def getPage(self, url): | |
74 return None | |
75 | |
76 def pageExists(self, url): | |
77 return False | |
78 | |
79 def getLinksTo(self, url): | |
80 return [] | |
81 | |
82 | |
83 class MockFileSystem(): | |
84 def __init__(self, structure=None, slugify=Page.title_to_url, logger=None): | |
85 if not structure: | |
86 structure = [] | |
87 if not slugify: | |
88 slugify = lambda x: x | |
89 self.structure = structure | |
90 self.slugify = slugify | |
91 self.logger = logger | |
92 self.excluded = [] | |
93 | |
94 def getPageInfos(self, subdir=None): | |
95 node = self._getNode(subdir) | |
96 for n in self._getChildren(node): | |
97 yield self._getPageInfo(n) | |
98 | |
99 def getPageInfo(self, path): | |
100 node = self._getNode(path) | |
101 return self._getPageInfo(node) | |
102 | |
103 def getPage(self, url): | |
104 path = self._getPath(url, True) | |
105 node = self._getNode(path) | |
106 return self._getPageInfo(node, True) | |
107 | |
108 def setPage(self, path, content): | |
109 pass | |
110 | |
111 def pageExists(self, url): | |
112 return False | |
113 | |
114 def getPhysicalNamespacePath(self, url): | |
115 return None | |
116 | |
117 def _getPageInfo(self, node, with_content=False): | |
118 path_split = os.path.splitext(node['path']) | |
119 url = self.slugify(path_split[0]) | |
120 info = { | |
121 'url': url, | |
122 'path': node['path'] | |
123 } | |
124 if with_content: | |
125 info['content'] = node['content'] | |
126 return info | |
127 | |
128 def _getNode(self, path): | |
129 node = self.structure | |
130 if path: | |
131 for n in path.split('/'): | |
132 node = node[n] | |
133 else: | |
134 path = '' | |
135 if isinstance(node, types.StringTypes): | |
136 return {'type': 'file', 'path': path, 'content': node} | |
137 return {'type': 'dir', 'path': path, 'content': node} | |
138 | |
139 def _getChildren(self, node): | |
140 if node['type'] != 'dir': | |
141 raise Exception("'%s' is not a directory." % node['path']) | |
142 for name in node['content']: | |
143 child_path = os.path.join(node['path'], name) | |
144 child = node['content'][name] | |
145 if isinstance(child, types.StringTypes): | |
146 yield { | |
147 'type': 'file', | |
148 'path': child_path, | |
149 'content': child | |
150 } | |
151 else: | |
152 for c in self._getChildren({ | |
153 'type': 'dir', | |
154 'path': child_path, | |
155 'content': child | |
156 }): | |
157 yield c | |
158 | |
159 def _getPath(self, url, is_file): | |
160 path = '' | |
161 current = self.structure | |
162 parts = unicode(url).lower().split('/') | |
163 for i, part in enumerate(parts): | |
164 for name in current: | |
165 name_slug = self.slugify(name) | |
166 if is_file and i == len(parts) - 1: | |
167 if re.match(r"%s\.[a-z]+" % re.escape(part), name_slug): | |
168 current = current[name] | |
169 path = os.path.join(path, name) | |
170 break | |
171 else: | |
172 if name_slug == part: | |
173 current = current[name] | |
174 path = os.path.join(path, name) | |
175 break | |
176 else: | |
177 # Failed to find a part of the URL. | |
178 raise PageNotFoundError("No such page: " + url) | |
179 return path | |
180 | |
181 @staticmethod | |
182 def save_structure(path, structure): | |
183 if not os.path.isdir(path): | |
184 os.makedirs(path) | |
185 for node in structure: | |
186 node_path = os.path.join(path, node) | |
187 if isinstance(structure[node], types.StringTypes): | |
188 with codecs.open(node_path, 'w', encoding='utf-8') as f: | |
189 f.write(structure[node]) | |
190 else: | |
191 MockFileSystem.save_structure(node_path, structure[node]) | |
192 | |
193 | |
194 class MockWikiIndex(WikiIndex): | |
195 def __init__(self, logger=None): | |
196 WikiIndex.__init__(self, logger) | |
197 | |
198 def initIndex(self): | |
199 pass | |
200 | |
201 def reset(self, pages): | |
202 pass | |
203 | |
204 def update(self, pages): | |
205 pass | |
206 | |
207 def search(self, query): | |
208 # url, title, content_highlights | |
209 return None | |
210 | |
211 | |
212 class MockSourceControl(SourceControl): | |
213 def __init__(self, logger=None): | |
214 SourceControl.__init__(self, logger) | |
215 | |
216 def initRepo(self): | |
217 pass | |
218 | |
219 def getSpecialFilenames(self): | |
220 return [] | |
221 | |
222 def getHistory(self, path=None): | |
223 return [] | |
224 | |
225 def getState(self, path): | |
226 raise NotImplementedError() | |
227 | |
228 def getRevision(self, path, rev): | |
229 raise NotImplementedError() | |
230 | |
231 def diff(self, path, rev1, rev2): | |
232 raise NotImplementedError() | |
233 | |
234 def commit(self, paths, op_meta): | |
235 raise NotImplementedError() | |
236 | |
237 def revert(self, paths=None): | |
238 raise NotImplementedError() |