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()