diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/mock.py	Mon Jan 28 23:13:04 2013 -0800
@@ -0,0 +1,238 @@
+import re
+import os.path
+import types
+import codecs
+import logging
+import StringIO
+from wikked.page import Page
+from wikked.fs import PageNotFoundError
+from wikked.db import Database
+from wikked.indexer import WikiIndex
+from wikked.scm import SourceControl
+
+
+class MockWikiParameters(object):
+    def __init__(self):
+        self.formatters = {
+            self._passthrough: ['txt', 'html']
+        }
+
+        self.config_text = ""
+        self.special_filenames = []
+
+        self.logger_factory = lambda: logging.getLogger('wikked.tests')
+        self.page_factory = lambda wiki, url: MockPage(wiki, url)
+        self.config_factory = lambda: StringIO.StringIO(self.config_text)
+        self.fs_factory = lambda cfg: MockFileSystem()
+        self.index_factory = lambda cfg: MockWikiIndex()
+        self.db_factory = lambda cfg: MockDatabase()
+        self.scm_factory = lambda cfg: MockSourceControl()
+
+    def getSpecialFilenames(self):
+        return self.special_filenames
+
+    def _passthrough(self, text):
+        return text
+
+
+class MockPage(Page):
+    def __init__(self, wiki, url):
+        Page.__init__(self, wiki, url)
+
+
+class MockDatabase(Database):
+    def __init__(self, content=None, logger=None):
+        Database.__init__(self, logger)
+        self.content = content
+        self._open_count = 0
+
+    def initDb(self):
+        pass
+
+    def open(self):
+        self._open_count += 1
+
+    def close(self):
+        self._open_count -= 1
+        if self._open_count < 0:
+            raise Exception(
+                "The database was closed more times than it was open.")
+
+    def reset(self, pages):
+        pass
+
+    def update(self, pages):
+        pass
+
+    def getPageUrls(self, subdir=None):
+        return []
+
+    def getPages(self, subdir=None):
+        return []
+
+    def getPage(self, url):
+        return None
+
+    def pageExists(self, url):
+        return False
+
+    def getLinksTo(self, url):
+        return []
+
+
+class MockFileSystem():
+    def __init__(self, structure=None, slugify=Page.title_to_url, logger=None):
+        if not structure:
+            structure = []
+        if not slugify:
+            slugify = lambda x: x
+        self.structure = structure
+        self.slugify = slugify
+        self.logger = logger
+        self.excluded = []
+
+    def getPageInfos(self, subdir=None):
+        node = self._getNode(subdir)
+        for n in self._getChildren(node):
+            yield self._getPageInfo(n)
+
+    def getPageInfo(self, path):
+        node = self._getNode(path)
+        return self._getPageInfo(node)
+
+    def getPage(self, url):
+        path = self._getPath(url, True)
+        node = self._getNode(path)
+        return self._getPageInfo(node, True)
+
+    def setPage(self, path, content):
+        pass
+
+    def pageExists(self, url):
+        return False
+
+    def getPhysicalNamespacePath(self, url):
+        return None
+
+    def _getPageInfo(self, node, with_content=False):
+        path_split = os.path.splitext(node['path'])
+        url = self.slugify(path_split[0])
+        info = {
+            'url': url,
+            'path': node['path']
+            }
+        if with_content:
+            info['content'] = node['content']
+        return info
+
+    def _getNode(self, path):
+        node = self.structure
+        if path:
+            for n in path.split('/'):
+                node = node[n]
+        else:
+            path = ''
+        if isinstance(node, types.StringTypes):
+            return {'type': 'file', 'path': path, 'content': node}
+        return {'type': 'dir', 'path': path, 'content': node}
+
+    def _getChildren(self, node):
+        if node['type'] != 'dir':
+            raise Exception("'%s' is not a directory." % node['path'])
+        for name in node['content']:
+            child_path = os.path.join(node['path'], name)
+            child = node['content'][name]
+            if isinstance(child, types.StringTypes):
+                yield {
+                    'type': 'file',
+                    'path': child_path,
+                    'content': child
+                    }
+            else:
+                for c in self._getChildren({
+                    'type': 'dir',
+                    'path': child_path,
+                    'content': child
+                    }):
+                    yield c
+
+    def _getPath(self, url, is_file):
+        path = ''
+        current = self.structure
+        parts = unicode(url).lower().split('/')
+        for i, part in enumerate(parts):
+            for name in current:
+                name_slug = self.slugify(name)
+                if is_file and i == len(parts) - 1:
+                    if re.match(r"%s\.[a-z]+" % re.escape(part), name_slug):
+                        current = current[name]
+                        path = os.path.join(path, name)
+                        break
+                else:
+                    if name_slug == part:
+                        current = current[name]
+                        path = os.path.join(path, name)
+                        break
+            else:
+                # Failed to find a part of the URL.
+                raise PageNotFoundError("No such page: " + url)
+        return path
+
+    @staticmethod
+    def save_structure(path, structure):
+        if not os.path.isdir(path):
+            os.makedirs(path)
+        for node in structure:
+            node_path = os.path.join(path, node)
+            if isinstance(structure[node], types.StringTypes):
+                with codecs.open(node_path, 'w', encoding='utf-8') as f:
+                    f.write(structure[node])
+            else:
+                MockFileSystem.save_structure(node_path, structure[node])
+
+
+class MockWikiIndex(WikiIndex):
+    def __init__(self, logger=None):
+        WikiIndex.__init__(self, logger)
+
+    def initIndex(self):
+        pass
+
+    def reset(self, pages):
+        pass
+
+    def update(self, pages):
+        pass
+
+    def search(self, query):
+        # url, title, content_highlights
+        return None
+
+
+class MockSourceControl(SourceControl):
+    def __init__(self, logger=None):
+        SourceControl.__init__(self, logger)
+
+    def initRepo(self):
+        pass
+
+    def getSpecialFilenames(self):
+        return []
+
+    def getHistory(self, path=None):
+        return []
+
+    def getState(self, path):
+        raise NotImplementedError()
+
+    def getRevision(self, path, rev):
+        raise NotImplementedError()
+
+    def diff(self, path, rev1, rev2):
+        raise NotImplementedError()
+
+    def commit(self, paths, op_meta):
+        raise NotImplementedError()
+
+    def revert(self, paths=None):
+        raise NotImplementedError()