changeset 2334:529b17ec4396

Merge with main.
author Karol 'grzywacz' Nowak <grzywacz@sul.uni.lodz.pl>
date Mon, 02 Jul 2007 13:15:50 +0200
parents 741ab277616a (current diff) 2aa65d5835d4 (diff)
children abcb89a89ad2
files MoinMoin/_tests/macro/test_Action.py MoinMoin/_tests/macro/test_Hits.py MoinMoin/_tests/macro/test_ImageLink.py MoinMoin/_tests/test_converter_text_html_text_moin_wiki.py MoinMoin/_tests/test_formatter.py MoinMoin/_tests/test_macro.py MoinMoin/_tests/test_mail_sendmail.py MoinMoin/_tests/test_parser_text_moin_wiki.py MoinMoin/_tests/test_request.py MoinMoin/_tests/test_search.py MoinMoin/_tests/test_security.py MoinMoin/_tests/test_widget_html.py MoinMoin/_tests/test_wikixml_marshal.py MoinMoin/_tests/test_xmlrpc_multicall.py MoinMoin/xmlrpc/_tests/test_multicall.py tests/rpctest.py
diffstat 43 files changed, 3227 insertions(+), 2984 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/Page.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/Page.py	Mon Jul 02 13:15:50 2007 +0200
@@ -734,8 +734,7 @@
 
         # look for the end of words and the start of a new word,
         # and insert a space there
-        split_re = re.compile('([%s])([%s])' % (config.chars_lower, config.chars_upper))
-        splitted = split_re.sub(r'\1 \2', self.page_name)
+        splitted = config.split_regex.sub(r'\1 \2', self.page_name)
         return splitted
 
     def url(self, request, querystr=None, anchor=None, relative=True, **kw):
--- a/MoinMoin/_tests/macro/test_Action.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    MoinMoin - MoinMoin.macro.Action Tests
-
-    @copyright: 2007 MoinMoin:ReimarBauer
-
-    @license: GNU GPL, see COPYING for details.
-"""
-import os
-from MoinMoin import macro
-from MoinMoin.macro import Action
-from MoinMoin.Page import Page
-from MoinMoin.PageEditor import PageEditor
-
-
-class TestAction:
-    """ testing macro Action calling action raw """
-
-    def setup_class(self):
-        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForAction'
-        self.page = PageEditor(self.request, self.pagename)
-        self.shouldDeleteTestPage = True
-
-    def teardown_class(self):
-        if self.shouldDeleteTestPage:
-            import shutil
-            page = Page(self.request, self.pagename)
-            fpath = page.getPagePath(use_underlay=0, check_create=0)
-            shutil.rmtree(fpath, True)
-
-            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
-            if os.path.exists(fpath):
-                os.remove(fpath)
-
-    def _make_macro(self):
-        """Test helper"""
-        from MoinMoin.parser.text import Parser
-        from MoinMoin.formatter.text_html import Formatter
-        p = Parser("##\n", self.request)
-        p.formatter = Formatter(self.request)
-        p.formatter.page = self.page
-        self.request.formatter = p.formatter
-        p.form = self.request.form
-        m = macro.Macro(p)
-        return m
-
-    def _createTestPage(self, body):
-        """ Create temporary page """
-        assert body is not None
-        self.request.reset()
-        self.page.saveText(body, 0)
-
-    def testActionCallingRaw(self):
-        """ module_tested: executes raw by macro Action on existing page"""
-
-        expected = '<a href="./AutoCreatedMoinMoinTemporaryTestPageForAction?action=raw">raw</a>'
-        text = '= title1 =\n||A||B||\n'
-        self._createTestPage(text)
-        m = self._make_macro()
-        result = Action.execute(m, 'raw')
-
-        assert result == expected
-
--- a/MoinMoin/_tests/macro/test_Hits.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.macro Hits tested
-
-    @copyright: 2007 MoinMoin:ReimarBauer
-
-    @license: GNU GPL, see COPYING for details.
-"""
-import os
-from MoinMoin import macro
-from MoinMoin.logfile import eventlog
-from MoinMoin.Page import Page
-from MoinMoin.PageEditor import PageEditor
-from MoinMoin.parser.text_moin_wiki import Parser
-
-class TestHits:
-    """Hits: testing Hits macro """
-
-    def setup_class(self):
-        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForHits'
-        self.page = PageEditor(self.request, self.pagename)
-        self.shouldDeleteTestPage = False
-        # for that test eventlog needs to be empty
-        fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
-        if os.path.exists(fpath):
-            os.remove(fpath)
-
-    def teardown_class(self):
-        if self.shouldDeleteTestPage:
-            import shutil
-            page = Page(self.request, self.pagename)
-            fpath = page.getPagePath(use_underlay=0, check_create=0)
-            shutil.rmtree(fpath, True)
-
-            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
-            if os.path.exists(fpath):
-                os.remove(fpath)
-
-    def _make_macro(self):
-        """Test helper"""
-        from MoinMoin.parser.text import Parser
-        from MoinMoin.formatter.text_html import Formatter
-        p = Parser("##\n", self.request)
-        p.formatter = Formatter(self.request)
-        p.formatter.page = self.page
-        self.request.formatter = p.formatter
-        p.form = self.request.form
-        m = macro.Macro(p)
-        return m
-
-    def _test_macro(self, name, args):
-        m = self._make_macro()
-        return m.execute(name, args)
-
-    def _createTestPage(self, body):
-        """ Create temporary page """
-        assert body is not None
-        self.request.reset()
-        self.page.saveText(body, 0)
-
-    def testHitsNoArg(self):
-        """ macro Hits test: 'no args for Hits (Hits is executed on current page) """
-        self.shouldDeleteTestPage = False
-        self._createTestPage('This is an example to test a macro')
-
-        # Three log entries for the current page and one for WikiSandBox simulating viewing
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': 'WikiSandBox'})
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
-
-        result = self._test_macro('Hits', '')
-        expected = "3"
-        assert result == expected
-
-    def testHitsForAll(self):
-        """ macro Hits test: 'all=1' for Hits (all pages are counted for VIEWPAGE) """
-        self.shouldDeleteTestPage = False
-        self._createTestPage('This is an example to test a macro with parameters')
-
-        # Two log entries for simulating viewing
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
-        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
-
-        result = self._test_macro('Hits', 'all=1')
-        expected = "6"
-        assert result == expected
-
-    def testHitsForFilter(self):
-        """ macro Hits test: 'all=1, filter=SAVEPAGE' for Hits (SAVEPAGE counted for current page)"""
-        self.shouldDeleteTestPage = False
-
-        # simulate a log entry SAVEPAGE for WikiSandBox to destinguish current page
-        eventlog.EventLog(self.request).add(self.request, 'SAVEPAGE', {'pagename': 'WikiSandBox'})
-        result = self._test_macro('Hits', 'filter=SAVEPAGE')
-        expected = "2"
-        assert result == expected
-
-    def testHitsForAllAndFilter(self):
-        """ macro test: 'all=1, filter=SAVEPAGE' for Hits (all pages are counted for SAVEPAGE)"""
-        self.shouldDeleteTestPage = True
-
-        result = self._test_macro('Hits', 'all=1, filter=SAVEPAGE')
-        expected = "3"
-        assert result == expected
-
-
--- a/MoinMoin/_tests/macro/test_ImageLink.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.macro ImageLink tested
-
-    @copyright: 2007 MoinMoin:ReimarBauer
-
-    @license: GNU GPL, see COPYING for details.
-"""
-import os
-from MoinMoin import macro
-from MoinMoin.logfile import eventlog
-from MoinMoin.Page import Page
-from MoinMoin.PageEditor import PageEditor
-from MoinMoin.parser.text_moin_wiki import Parser
-
-class TestHits:
-    """Hits: testing Hits macro """
-
-    def setup_class(self):
-        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForImageLink'
-        self.page = PageEditor(self.request, self.pagename)
-        self.shouldDeleteTestPage = False
-
-    def teardown_class(self):
-        if self.shouldDeleteTestPage:
-            import shutil
-            page = Page(self.request, self.pagename)
-            fpath = page.getPagePath(use_underlay=0, check_create=0)
-            shutil.rmtree(fpath, True)
-
-            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
-            if os.path.exists(fpath):
-                os.remove(fpath)
-
-    def _make_macro(self):
-        """Test helper"""
-        from MoinMoin.parser.text import Parser
-        from MoinMoin.formatter.text_html import Formatter
-        p = Parser("##\n", self.request)
-        p.formatter = Formatter(self.request)
-        p.formatter.page = self.page
-        self.request.formatter = p.formatter
-        p.form = self.request.form
-        m = macro.Macro(p)
-        return m
-
-    def _test_macro(self, name, args):
-        m = self._make_macro()
-        return m.execute(name, args)
-
-    def _createTestPage(self, body):
-        """ Create temporary page """
-        assert body is not None
-        self.request.reset()
-        self.page.saveText(body, 0)
-
-    def testImageLinkNoArg(self):
-        """ macro ImageLink test: 'no args for ImageLink (ImageLink is executed on FrontPage) """
-        #self._createTestPage('This is an example to test a macro')
-        result = self._test_macro('ImageLink', '')
-        expected = '<div class="message">Not enough arguments to ImageLink macro! e.g. [[ImageLink(example.png, WikiName, width=200)]].</div>'
-        assert result == expected
-
-    def testImageLinkTwoParamsNoKeyword(self):
-        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, FrontPage)]] """
-        self.shouldDeleteTestPage = False
-
-        result = self._test_macro('ImageLink', 'http://static.wikiwikiweb.de/logos/moindude.png, FrontPage')
-        expected = '<a href="./FrontPage"><img alt="FrontPage" src="http://static.wikiwikiweb.de/logos/moindude.png" title="FrontPage" /></a>'
-        assert result == expected
-
-    def testImageLinkTwoParamsOneKeyword(self):
-        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage)]] 
-        order of keywords to parameter list is independent 
-        """
-        self.shouldDeleteTestPage = True 
-
-        result = self._test_macro('ImageLink', 'http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage')
-        expected = '<a href="./FrontPage"><img alt="The old dude" src="http://static.wikiwikiweb.de/logos/moindude.png" title="The old dude" /></a>'
-        assert result == expected
-
-
-
--- a/MoinMoin/_tests/test_Page.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/_tests/test_Page.py	Mon Jul 02 13:15:50 2007 +0200
@@ -2,24 +2,62 @@
 """
     MoinMoin - MoinMoin.Page Tests
 
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @copyright: 2007 MoinMoin:ThomasWaldmann
     @license: GNU GPL, see COPYING for details.
 """
 
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from MoinMoin import Page
+import py
 
-class TestExists(unittest.TestCase):
-    """Page: testing wiki page"""
+from MoinMoin.Page import Page
+
+class TestPage:
+    def testMeta(self):
+        page = Page(self.request, u'FrontPage')
+        meta = page.meta
+        for k, v in meta:
+            if k == u'format':
+                assert v == u'wiki'
+            elif k == u'language':
+                assert v == u'en'
+
+    def testBody(self):
+        page = Page(self.request, u'FrontPage')
+        body = page.body
+        assert type(body) is unicode
+        assert 'MoinMoin' in body
+        assert body.endswith('\n')
+        assert '\r' not in body
 
     def testExists(self):
-        """ Page: page.exists() finds existing pages only """
-        tests = (
-            # Page name,                            expected
-            ('FrontPage',                           1),
-            ('OnlyAnIdiotWouldCreateSuchaPage',     0),
-            )
-        for name, expected in tests:
-            pg = Page.Page(self.request, name)
-            self.assertEqual(pg.exists(), expected,
-                             '%s should%s exist' % (name, (' not', '')[expected]))
+        assert Page(self.request, 'FrontPage').exists()
+        assert not Page(self.request, 'ThisPageDoesNotExist').exists()
+        assert not Page(self.request, '').exists()
+
+    def testLastEdit(self):
+        page = Page(self.request, u'FrontPage')
+        last_edit = page.last_edit(self.request)
+        assert 'editor' in last_edit
+        assert 'timestamp' in last_edit
+
+    def testSplitTitle(self):
+        page = Page(self.request, u"FrontPage")
+        assert page.split_title(force=True) == u'Front Page'
+
+    def testGetRevList(self):
+        page = Page(self.request, u"FrontPage")
+        assert page.getRevList() == [1]
+
+    def testGetPageLinks(self):
+        page = Page(self.request, u"FrontPage")
+        assert u'WikiSandBox' in page.getPageLinks(self.request)
+
+
+class TestRootPage:
+    def testPageList(self):
+        rootpage = self.request.rootpage
+        pagelist = rootpage.getPageList()
+        assert len(pagelist) > 100
+        assert u'FrontPage' in pagelist
+        assert u'' not in pagelist
+
+
--- a/MoinMoin/_tests/test_converter_text_html_text_moin_wiki.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1136 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-MoinMoin - MoinMoin.text_html_text_moin_wiki Tests
-
-@copyright: 2005 by Bastian Blank, ThomasWaldmann
-@license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-
-import py
-py.test.skip("Many broken tests, much broken code, broken, broken, broken.")
-
-from cStringIO import StringIO
-from MoinMoin.converter import text_html_text_moin_wiki as converter
-from MoinMoin.parser.text_moin_wiki import Parser
-from MoinMoin.formatter.text_gedit import Formatter
-from MoinMoin.request import Clock
-from MoinMoin.error import ConvertError
-
-convert = converter.convert
-error = ConvertError
-
-
-class TestBase(unittest.TestCase):
-
-    def setUp(self):
-        self.cfg = self.TestConfig(bang_meta=True)
-        
-    def tearDown(self):
-        del self.cfg
-
-    def do_convert_real(self, func_args, successful=True):
-        try:
-            ret = convert(*func_args)
-        except error, e:
-            if successful:
-                self.fail("fails with parse error: %s" % e)
-            else:
-                return
-        if successful:
-            return ret
-        else:
-            self.fail("doesn't fail with parse error")
-
-
-class MinimalPage(object):
-    def __init__(self):
-        self.hilite_re = None
-        self.page_name = "testpage"
-
-
-class MinimalRequest(object):
-    # TODO: do we really need this class? no other test uses a request replacement.
-
-    def __init__(self, request):
-        self.request = request
-        self.clock = Clock()
-        
-        # This is broken - tests that need correct content_lang will fail
-        self.content_lang = None
-        self.current_lang = None
-        
-        self.form = {}
-        self._page_headings = {}
-        self.result = []
-
-    def getText(self, text, formatted=True):
-        return text
-
-    def write(self, text):
-        self.result.append(text)
-
-    def __getattr__(self, name):
-        return getattr(self.request, name)
-
-
-class TestConvertBlockRepeatable(TestBase):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        self.failUnlessEqual(text, out)
-
-    def testComment01(self):
-        test = ur"""
-##test
-"""
-        output = u"""<pre class="comment">\n##test</pre>"""
-        self.do(test, output)
-
-    def testComment02(self):
-        test = ur"""
-##test
-##test
-"""
-        output = u"""
-<pre class="comment">\n##test</pre>
-<pre class="comment">\n##test</pre>
-"""
-        self.do(test, output)
-
-    def testHeading01(self):
-        test = ur"""
-= test1 =
-
-"""
-        output = ur"""
-<h2>test1</h2>
-"""
-        self.do(test, output)
-
-    def testHeading02(self):
-        test = ur"""
-= test1 =
-
-== test2 ==
-
-"""
-        output = ur"""
-<h2>test1</h2>
-<h3>test2</h3>
-"""
-        self.do(test, output)
-
-    def testListSuccess01(self):
-        test = ur"""
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess02(self):
-        test = ur"""
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess03(self):
-        test = ur"""
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess04(self):
-        test = ur"""
- * test
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess05(self):
-        test = ur"""
- 1. test
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess06(self):
-        test = ur"""
- test:: test
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess07(self):
-        test = ur"""
- * test
-  
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess08(self):
-        test = ur"""
- 1. test
-  
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess09(self):
-        test = ur"""
- test:: test
-  
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess10(self):
-        test = ur"""
- * test
-  * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess11(self):
-        test = ur"""
- 1. test
-  1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess12(self):
-        test = ur"""
- test:: test
-  test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess13(self):
-        test = ur"""
- * test
-  * test
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess14(self):
-        test = ur"""
- 1. test
-  1. test
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-</li>
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess15(self):
-        test = ur"""
- test:: test
-  test:: test
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-</dd>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess16(self):
-        test = ur"""
- * test
-
- 1. test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess17(self):
-        test = ur"""
- * test
-
- test:: test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess18(self):
-        test = ur"""
- 1. test
-
- * test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess19(self):
-        test = ur"""
- 1. test
-
- test:: test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess20(self):
-        test = ur"""
- test:: test
-
- * test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess21(self):
-        test = ur"""
- test:: test
-
- 1. test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess23(self):
-        test = ur"""
- 1. test
-  * test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess26(self):
-        test = ur"""
- * test
-
-test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testListSuccess28(self):
-        test = ur"""
- * test
-
- test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess29(self):
-        test = ur"""
- * test
-  * test
- test
-"""
-        output = ur"""
-"""
-        self.do(test, output)
-
-    def testListSuccess30(self):
-        test = ur"""
- * test
-  * test
-  test
-"""
-        output = ur"""
-"""
-        self.do(test, output)
-
-    def testParagraph1(self):
-        test = ur"""
-test
-
-"""
-        output = ur"""
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testParagraph2(self):
-        test = ur"""
-test
-
-test
-
-"""
-        output = ur"""
-<p>test </p>
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testPreSuccess1(self):
-        test = ur"""
-{{{
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess2(self):
-        test = ur"""
-{{{
-test
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess3(self):
-        test = ur"""
-{{{
-test
-
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess4(self):
-        test = ur"""
-{{{
- * test
-}}}
-
-"""
-        output = ur"""
-<pre>
- * test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess5(self):
-        test = ur"""
-{{{
-  }}}
-
-"""
-        output = ur"""
-<pre>
-  </pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess6(self):
-        test = ur"""
- * {{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li>
-<pre>
-test
-</pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess7(self):
-        test = ur"""
- * {{{
-   test
-   }}}
-
-"""
-        output = ur"""
-<ul>
-<li>
-<pre>
-   test
-   </pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess8(self):
-        test = ur"""
- * test
- {{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li><p>test 
-</p>
-<pre>
-test
-</pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess9(self):
-        test = ur"""
- * test
-
-{{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-
-<pre>
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testRule1(self):
-        test = ur"""
-----
-
-"""
-        output = ur"""
-<hr/>
-"""
-        self.do(test, output)
-
-    def testTable01(self):
-        test = ur"""
-|| ||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p> </p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable02(self):
-        test = ur"""
-||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable03(self):
-        test = ur"""
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable04(self):
-        test = ur"""
-||test||
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable05(self):
-        test = ur"""
-||||test||
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable06(self):
-        test = ur"""
-||||test||test||
-||test||||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-class TestConvertInlineFormatRepeatable(TestBase):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        output = "<p>%s </p>" % output
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        out = out.rstrip('\n')
-        self.failUnlessEqual(text, out)
-
-    def testEmphasis01(self):
-        test = ur"''test''"
-        output = ur"<em>test</em>"
-        self.do(test, output)
-
-    def testEmphasis02(self):
-        test = ur"'''test'''"
-        output = ur"<strong>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis03(self):
-        test = ur"'''''test'''''"
-        output = ur"<em><strong>test</strong></em>"
-        self.do(test, output)
-
-    def testEmphasis04(self):
-        test = ur"''test'''test'''''"
-        output = ur"<em>test<strong>test</strong></em>"
-        self.do(test, output)
-
-    def testEmphasis05(self):
-        test = ur"'''test''test'''''"
-        output = ur"<strong>test<em>test</em></strong>"
-        self.do(test, output)
-
-    def testEmphasis06(self):
-        test = ur"''test'''test'''test''"
-        output = ur"<em>test<strong>test</strong>test</em>"
-        self.do(test, output)
-
-    def testEmphasis07(self):
-        test = ur"'''test''test''test'''"
-        output = ur"<strong>test<em>test</em>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis08(self):
-        test = ur"''test'''''test'''"
-        output = ur"<em>test</em><strong>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis09(self):
-        test = ur"'''test'''''test''"
-        output = ur"<strong>test</strong><em>test</em>"
-        self.do(test, output)
-
-    def testEmphasis10(self):
-        test = ur"'''''test''test'''"
-        output = ur"<strong><em>test</em>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis11(self):
-        test = ur"'''''test'''test''"
-        output = ur"<em><strong>test</strong>test</em>"
-        self.do(test, output)
-
-    def testFormatBig01(self):
-        test = ur"~+test+~"
-        output = ur"<big>test</big>"
-        self.do(test, output)
-
-    def testFormatSmall01(self):
-        test = ur"~-test-~"
-        output = ur"<small>test</small>"
-        self.do(test, output)
-
-    def testFormatStrike01(self):
-        test = ur"--(test)--"
-        output = ur"<strike>test</strike>"
-        self.do(test, output)
-
-    def testFormatSub01(self):
-        test = ur",,test,,"
-        output = ur"<sub>test</sub>"
-        self.do(test, output)
-
-    def testFormatSup01(self):
-        test = ur"^test^"
-        output = ur"<sup>test</sup>"
-        self.do(test, output)
-
-    def testFormatUnderline01(self):
-        test = ur"__test__"
-        output = ur"<u>test</u>"
-        self.do(test, output)
-
-    def testPre01(self):
-        test = ur"{{{test}}}"
-        output = ur"<tt>test</tt>"
-        self.do(test, output)
-
-    def testWhitespace01(self):
-        test = ur"''test '''test'''''"
-        output = ur"<em>test <strong>test</strong></em>"
-        self.do(test, output)
-
-class TestConvertInlineItemRepeatable(TestBase):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        output = "<p>%s </p>" % output
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        out = out.rstrip('\n')
-        self.failUnlessEqual(text, out)
-
-    def testWikiWord01(self):
-        test = ur"WikiWord"
-        output = ur"""<a class="nonexistent" href="./WikiWord">WikiWord</a>"""
-        self.do(test, output)
-
-    def testNoWikiWord01(self):
-        test = ur"!WikiWord"
-        output = ur"WikiWord"
-        self.do(test, output)
-
-    def testSmiley01(self):
-        test = ur":-)"
-        output = ur"""<img src="/wiki/modern/img/smile.png" alt=":-)" height="15" width="15">"""
-        self.do(test, output)
-
-class TestStrip(unittest.TestCase):
-    def do(self, cls, text, output):
-        tree = converter.parse(text)
-        cls().do(tree)
-        out = StringIO()
-        try:
-            import xml.dom.ext
-        except ImportError:
-            py.test.skip('xml.dom.ext module is not available')
-        xml.dom.ext.Print(tree, out)
-        self.failUnlessEqual("<?xml version='1.0' encoding='UTF-8'?>%s" % output, out.getvalue().decode("utf-8"))
-
-class TestStripWhitespace(TestStrip):
-    def do(self, text, output):
-        super(TestStripWhitespace, self).do(converter.strip_whitespace, text, output)
-
-    def test1(self):
-        test = ur"""
-<t/>
-"""
-        output = ur"""<t/>"""
-        self.do(test, output)
-
-    def test2(self):
-        test = ur"""
-<t>
-  <z/>
-</t>
-"""
-        output = ur"""<t><z/></t>"""
-        self.do(test, output)
-
-    def test3(self):
-        test = ur"""
-<t>
-  <z>test</z>
-</t>
-"""
-        output = ur"""<t><z>test</z></t>"""
-        self.do(test, output)
-
-    def test4(self):
-        test = ur"""<p>&nbsp;</p>"""
-        output = ur""""""
-        self.do(test, output)
-
-    def test5(self):
-        test = ur"""<p>test </p>"""
-        output = ur"""<p>test</p>"""
-        self.do(test, output)
-
-class TestConvertBrokenBrowser(TestBase):
-    def do(self, text, output):
-        text = text.strip('\n')
-        output = output.lstrip('\n')
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        out = self.do_convert_real([request, page.page_name, text])
-        self.failUnlessEqual(output, out)
-
-    def testList01(self):
-        test = ur"""
-<ul>
-<li>test</li>
-<ul>
-<li>test</li>
-</ul>
-<li>test</li>
-</ul>
-"""
-        output = ur"""
- * test
-  * test
- * test
-
-"""
-        self.do(test, output)
-
--- a/MoinMoin/_tests/test_formatter.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.formatter.* Tests
-
-    @copyright: 2005 by MoinMoin:AlexanderSchremmer
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import py
-
-import re
-
-from MoinMoin.Page import Page
-from MoinMoin import wikiutil
-
-
-class TestFormatter:
-    def testSyntaxReferenceDomXml(self):
-        py.test.skip("dom_xml formatter is known to be broken")
-        f_name = 'dom_xml'
-        try:
-            formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
-        except wikiutil.PluginAttributeError:
-            pass
-        else:
-            print "Formatting using %r" % formatter
-            self.formatPage("SyntaxReference", formatter)
-            print "Done."
-
-    def testSyntaxReferenceDocBook(self):
-        py.test.skip("breaks with an attribute error, it should be checked whether the formatter on the DB branch is broken as well")
-        try:
-            from xml.dom import getDOMImplementation
-            dom = getDOMImplementation("4DOM")
-        except ImportError:
-            # if we don't have 4suite installed, the docbook formatter would just raise an exception
-            py.test.skip("not testing docbook formatter because no 4suite installed")
-        else:
-            f_name = 'text_docbook'
-            try:
-                formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
-            except wikiutil.PluginAttributeError:
-                pass
-            else:
-                print "Formatting using %r" % formatter
-                self.formatPage("SyntaxReference", formatter)
-                print "Done."
-
-    def testSyntaxReferenceOthers(self):
-        formatters = wikiutil.getPlugins("formatter", self.request.cfg)
-
-        # we have separate tests for those:
-        formatters.remove('text_docbook')
-        formatters.remove('dom_xml')
-
-        for f_name in formatters:
-            try:
-                formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
-            except wikiutil.PluginAttributeError:
-                pass
-            else:
-                print "Formatting using %r" % formatter
-                self.formatPage("SyntaxReference", formatter)
-                print "Done."
-
-    def formatPage(self, pagename, formatter):
-        """Parse a page. Should not raise an exception if the API of the
-        formatter is correct.
-        """
-
-        self.request.reset()
-        page = Page(self.request, pagename, formatter=formatter)
-        self.request.formatter = page.formatter = formatter(self.request)
-        #page.formatter.setPage(page)
-        #page.hilite_re = None
-
-        return self.request.redirectedOutput(page.send_page, content_only=1)
-
--- a/MoinMoin/_tests/test_macro.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.macro Tests
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>,
-                2006 MoinMoin:ThomasWaldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-
-from MoinMoin import macro
-from MoinMoin.parser.text import Parser
-from MoinMoin.formatter.text_html import Formatter
-
-
-class TestMacro(unittest.TestCase):
-    def testTrivialMacro(self):
-        """macro: trivial macro works"""
-        m = self._make_macro()
-        expected = m.formatter.linebreak(0)
-        result = m.execute("BR", "")
-        self.assertEqual(result, expected,
-            'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def _make_macro(self):
-        """Test helper"""
-        p = Parser("##\n", self.request)
-        p.formatter = Formatter(self.request)
-        self.request.formatter = p.formatter
-        p.form = self.request.form
-        m = macro.Macro(p)
-        return m
-
--- a/MoinMoin/_tests/test_mail_sendmail.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    MoinMoin - MoinMoin.mail.sendmail Tests
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from email.Charset import Charset, QP
-from email.Header import Header
-from MoinMoin.mail import sendmail
-from MoinMoin import config
-
-
-class TestdecodeSpamSafeEmail(unittest.TestCase):
-    """mail.sendmail: testing mail"""
-
-    _tests = (
-        ('', ''),
-        ('AT', '@'),
-        ('DOT', '.'),
-        ('DASH', '-'),
-        ('CAPS', ''),
-        ('Mixed', 'Mixed'),
-        ('lower', 'lower'),
-        ('Firstname DOT Lastname AT example DOT net',
-         'Firstname.Lastname@example.net'),
-        ('Firstname . Lastname AT exa mp le DOT n e t',
-         'Firstname.Lastname@example.net'),
-        ('Firstname I DONT WANT SPAM . Lastname@example DOT net',
-         'Firstname.Lastname@example.net'),
-        ('First name I Lastname DONT AT WANT SPAM example DOT n e t',
-         'FirstnameLastname@example.net'),
-        ('first.last@example.com', 'first.last@example.com'),
-        ('first . last @ example . com', 'first.last@example.com'),
-        )
-
-    def testDecodeSpamSafeMail(self):
-        """mail.sendmail: decoding spam safe mail"""
-        for coded, expected in self._tests:
-            result = sendmail.decodeSpamSafeEmail(coded)
-            self.assertEqual(result, expected,
-                             'Expected "%(expected)s" but got "%(result)s"' %
-                             locals())
-
-
-class TestEncodeAddress(unittest.TestCase):
-    """ Address encoding tests
-    
-    See http://www.faqs.org/rfcs/rfc2822.html section 3.4. 
-    Address Specification.
-            
-    mailbox     =   name-addr / addr-spec
-    name-addr   =   [display-name] angle-addr
-    angle-addr  =   [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
-    """
-    charset = Charset(config.charset)
-    charset.header_encoding = QP
-    charset.body_encoding = QP
-
-    def testSimpleAddress(self):
-        """ mail.sendmail: encode simple address: local@domain """
-        address = u'local@domain'
-        expected = address.encode(config.charset)
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
-    def testComposite(self):
-        """ mail.sendmail: encode address: 'Phrase <local@domain>' """
-        address = u'Phrase <local@domain>'
-        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
-        expected = phrase + '<local@domain>'
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
-    def testCompositeUnicode(self):
-        """ mail.sendmail: encode Uncode address: 'ויקי <local@domain>' """
-        address = u'ויקי <local@domain>'
-        phrase = str(Header(u'ויקי '.encode('utf-8'), self.charset))
-        expected = phrase + '<local@domain>'
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
-    def testEmptyPhrase(self):
-        """ mail.sendmail: encode address with empty phrase: '<local@domain>' """
-        address = u'<local@domain>'
-        expected = address.encode(config.charset)
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
-    def testEmptyAddress(self):
-        """ mail.sendmail: encode address with empty address: 'Phrase <>' 
-        
-        Let the smtp server handle this. We may raise error in such
-        case, but we don't do error checking for mail addresses.
-        """
-        address = u'Phrase <>'
-        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
-        expected = phrase + '<>'
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
-    def testInvalidAddress(self):
-        """ mail.sendmail: encode invalid address 'Phrase <blah' 
-        
-        Assume that this is a simple address. This address will
-        probably cause an error when trying to send mail. Junk in, junk
-        out.
-        """
-        address = u'Phrase <blah'
-        expected = address.encode(config.charset)
-        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
-                             expected)
-
--- a/MoinMoin/_tests/test_parser_text_moin_wiki.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,475 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.parser.text_moin_wiki Tests
-
-    TODO: these are actually parser+formatter tests. We should have
-    parser only tests here.
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-import re
-from StringIO import StringIO
-
-import py
-
-from MoinMoin.Page import Page
-from MoinMoin.parser.text_moin_wiki import Parser
-
-
-class ParserTestCase(unittest.TestCase):
-    """ Helper class that provide a parsing method """
-    
-    def parse(self, body):
-        """Parse body and return html
-
-        Create a page with body, then parse it and format using html formatter
-        """
-        assert body is not None
-        self.request.reset()
-        page = Page(self.request, 'ThisPageDoesNotExistsAndWillNeverBeReally')
-        page.set_raw_body(body)
-        from MoinMoin.formatter.text_html import Formatter
-        page.formatter = Formatter(self.request)
-        self.request.formatter = page.formatter
-        page.formatter.setPage(page)
-        page.hilite_re = None
-        
-        output = StringIO()
-        saved_write = self.request.write
-        self.request.write = output.write
-        try:
-            Parser(body, self.request).format(page.formatter)
-        finally:
-            self.request.write = saved_write
-        return output.getvalue()
-
-
-class TestParagraphs(ParserTestCase):
-    """ Test paragraphs creating
-
-    All tests ignoring white space in output
-    """
-
-    def testFirstParagraph(self):
-        """ parser.wiki: first paragraph should be in <p> """
-        py.test.skip("Broken because of line numbers")
-        result = self.parse('First')
-        expected = re.compile(r'<p>\s*First\s*</p>')
-        self.assert_(expected.search(result),
-                      '"%s" not in "%s"' % (expected.pattern, result))
-
-    def testEmptyLineBetweenParagraphs(self):
-        """ parser.wiki: empty line separates paragraphs """
-        py.test.skip("Broken because of line numbers")
-        result = self.parse('First\n\nSecond')
-        expected = re.compile(r'<p>\s*Second\s*</p>')
-        self.assert_(expected.search(result),
-                     '"%s" not in "%s"' % (expected.pattern, result))
-        
-    def testParagraphAfterBlockMarkup(self):
-        """ parser.wiki: create paragraph after block markup """
-        py.test.skip("Broken because of line numbers")
-
-        markup = (
-            '----\n',
-            '[[en]]\n',
-            '|| table ||\n',
-            '= heading 1 =\n',
-            '== heading 2 ==\n',
-            '=== heading 3 ===\n',
-            '==== heading 4 ====\n',
-            '===== heading 5 =====\n',
-            )
-        for item in markup:
-            text = item + 'Paragraph'
-            result = self.parse(text)
-            expected = re.compile(r'<p.*?>\s*Paragraph\s*</p>')
-            self.assert_(expected.search(result),
-                         '"%s" not in "%s"' % (expected.pattern, result))
-
-
-class TestHeadings(ParserTestCase):
-    """ Test various heading problems """
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = self.TestConfig(show_section_numbers=0)
-    
-    def tearDown(self):
-        del self.config
-
-    def testIgnoreWhiteSpaceAroundHeadingText(self):
-        """ parser.wiki: ignore white space around heading text
-
-        See bug: TableOfContentsBreakOnExtraSpaces.
-
-        Does not test mapping of '=' to h number, or valid html markup.
-        """
-        py.test.skip("Broken because of line numbers")
-        tests = (
-            '=  head =\n', # leading
-            '= head  =\n', # trailing
-            '=  head  =\n' # both
-                 )
-        expected = self.parse('= head =')
-        for test in tests:            
-            result = self.parse(test)
-            self.assertEqual(result, expected,
-                'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class TestTOC(ParserTestCase):
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = self.TestConfig(show_section_numbers=0)
-    
-    def tearDown(self):
-        del self.config
-
-    def testHeadingWithWhiteSpace(self):
-        """ parser.wiki: TOC links to headings with white space
-        
-        See bug: TableOfContentsBreakOnExtraSpaces.
-
-        Does not test TOC or heading formating, just verify that spaces
-        around heading text does not matter.
-        """
-        standard = """
-[[TableOfContents]]
-= heading =
-Text
-"""
-        withWhitespace = """
-[[TableOfContents]]
-=   heading   =
-Text
-"""
-        expected = self.parse(standard)
-        result = self.parse(withWhitespace)
-        self.assertEqual(result, expected,
-            'Expected "%(expected)s" but got "%(result)s"' % locals())
-        
-
-class TestDateTimeMacro(ParserTestCase):
-   """ Test DateTime macro
-
-   Might fail due to libc problems, therefore the fail message warn
-   about this.
-
-   TODO: when this test fail, does it mean that moin code fail on that
-   machine? - can we fix this?
-   """
-   
-   text = 'AAA %s AAA'
-   needle = re.compile(text %  r'(.+)')
-   _tests = (
-       # test                                   expected
-       ('[[DateTime(1970-01-06T00:00:00)]]',   '1970-01-06 00:00:00'),
-       ('[[DateTime(259200)]]',                '1970-01-04 00:00:00'),
-       ('[[DateTime(2003-03-03T03:03:03)]]',   '2003-03-03 03:03:03'),
-       ('[[DateTime(2000-01-01T00:00:00Z)]]',  '2000-01-01 00:00:00'),
-       ('[[Date(2002-02-02T01:02:03Z)]]',      '2002-02-02'),
-       )
-
-   def setUp(self):
-       """ Require default date and time format config values """
-       self.config = self.TestConfig(defaults=('date_fmt', 'datetime_fmt'))
-   
-   def tearDown(self):
-       del self.config
-   
-   def testDateTimeMacro(self):
-       """ parser.wiki: DateTime macro """
-       note = """
-   
-   If this fails, it is likely a problem in your python / libc,
-   not in moin.  See also:
-   <http://sourceforge.net/tracker/index.php?func=detail&
-       aid=902172&group_id=5470&atid=105470>"""
-
-       for test, expected in self._tests:
-           html = self.parse(self.text % test)
-           result = self.needle.search(html).group(1)
-           self.assertEqual(result, expected,
-               'Expected "%(expected)s" but got "%(result)s"; %(note)s' % locals())
-                       
-
-class TestTextFormatingTestCase(ParserTestCase):
-    """ Test wiki markup """
-    
-    text = 'AAA %s AAA'
-    needle = re.compile(text %  r'(.+)')
-    _tests = (
-        # test,                     expected
-        ('no format',               'no format'),
-        ("''em''",                  '<em>em</em>'),
-        ("'''bold'''",              '<strong>bold</strong>'),
-        ("__underline__",           '<span class="u">underline</span>'),
-        ("'''''Mix''' at start''",  '<em><strong>Mix</strong> at start</em>'),
-        ("'''''Mix'' at start'''",  '<strong><em>Mix</em> at start</strong>'),
-        ("'''Mix at ''end'''''",    '<strong>Mix at <em>end</em></strong>'),
-        ("''Mix at '''end'''''",    '<em>Mix at <strong>end</strong></em>'),
-        )
-    
-    def testTextFormating(self):
-        """ parser.wiki: text formating """
-        for test, expected in self._tests:
-            html = self.parse(self.text % test)
-            result = self.needle.search(html).group(1)
-            self.assertEqual(result, expected,
-                             'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class TestCloseInlineTestCase(ParserTestCase):
-
-    def testCloseOneInline(self):
-        """ parser.wiki: close open inline tag when block close """
-        py.test.skip("Broken because of line numbers")
-        cases = (
-            # test, expected
-            ("text'''text\n", r"<p>text<strong>text\s*</strong></p>"),
-            ("text''text\n", r"<p>text<em>text\s*</em></p>"),
-            ("text__text\n", r"<p>text<span class=\"u\">text\s*</span></p>"),
-            ("text ''em '''em strong __em strong underline",
-             r"text <em>em <strong>em strong <span class=\"u\">em strong underline"
-             r"\s*</span></strong></em></p>"),
-            )
-        for test, expected in cases:
-            needle = re.compile(expected)
-            result = self.parse(test)
-            self.assert_(needle.search(result),
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class TestInlineCrossing(ParserTestCase):
-    """
-    This test case fail with current parser/formatter and should be fixed in 2.0
-    """
-    
-    def disabled_testInlineCrossing(self):
-        """ parser.wiki: prevent inline crossing <a><b></a></b> """
-
-        expected = ("<p><em>a<strong>ab</strong></em><strong>b</strong>\s*</p>")
-        test = "''a'''ab''b'''\n"
-        needle = re.compile(expected)
-        result = self.parse(test)
-        self.assert_(needle.search(result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-       
-
-class TestEscapeHTML(ParserTestCase):
-    
-    def testEscapeInTT(self):
-        """ parser.wiki: escape html markup in `tt` """
-        test = 'text `<escape-me>` text\n'
-        self._test(test)
-
-    def testEscapeInTT2(self):
-        """ parser.wiki: escape html markup in {{{tt}}} """
-        test = 'text {{{<escape-me>}}} text\n'
-        self._test(test)
-
-    def testEscapeInPre(self):
-        """ parser.wiki: escape html markup in pre """
-        test = '''{{{
-<escape-me>
-}}}
-'''
-        self._test(test)
-        
-    def testEscapeInPreHashbang(self):
-        """ parser.wiki: escape html markup in pre with hashbang """
-        test = '''{{{#!
-<escape-me>
-}}}
-'''
-        self._test(test)
-        
-    def testEscapeInPythonCodeArea(self):
-        """ parser.wiki: escape html markup in python code area """
-        test = '''{{{#!python
-#<escape-me>
-}}}
-'''
-        self._test(test)
-
-    def testEscapeInGetTextMacro(self):
-        """ parser.wiki: escape html markup in GetText macro """
-        test = "text [[GetText(<escape-me>)]] text"
-        self._test(test)
-
-    def testEscapeInGetTextFormatted(self):
-        """ parser.wiki: escape html markup in getText formatted call """
-        test = self.request.getText('<escape-me>', formatted=1)
-        self._test(test)
-
-    def testEscapeInGetTextFormatedLink(self):
-        """ parser.wiki: escape html markup in getText formatted call with link """
-        test = self.request.getText('["<escape-me>"]', formatted=1)
-        self._test(test)
-
-    def testEscapeInGetTextUnFormatted(self):
-        """ parser.wiki: escape html markup in getText non formatted call """
-        test = self.request.getText('<escape-me>', formatted=0)
-        self._test(test)
-
-    def _test(self, test):
-        expected = r'&lt;escape-me&gt;'
-        result = self.parse(test)
-        self.assert_(re.search(expected, result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
-
-
-class TestEscapeWikiTableMarkup(ParserTestCase):
-
-    def testEscapeInTT(self):
-        """ parser.wiki: escape wiki table markup in `tt` """
-        test = 'text `||<tablewidth="80"> Table ||` text\n'
-        self.do(test)
-
-    def testEscapeInTT2(self):
-        """ parser.wiki: escape wiki table markup in {{{tt}}} """
-        test = 'text {{{||<tablewidth="80"> Table ||}}} text\n'
-        self.do(test)
-
-    def testEscapeInPre(self):
-        """ parser.wiki: escape wiki table  markup in pre """
-        test = '''{{{
-||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-        
-    def testEscapeInPreHashbang(self):
-        """ parser.wiki: escape wiki table  markup in pre with hashbang """
-        test = '''{{{#!
-||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-        
-    def testEscapeInPythonCodeArea(self):
-        """ parser.wiki: escape wiki table markup in python code area """
-        test = '''{{{#!python
-# ||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-
-    def do(self, test):
-        expected = r'&lt;tablewidth="80"&gt;'
-        result = self.parse(test)
-        self.assert_(re.search(expected, result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
-
-
-class TestRule(ParserTestCase):
-    """ Test rules markup """
-
-    def testNotRule(self):
-        """ parser.wiki: --- is no rule """
-        py.test.skip("Broken because of line numbers")
-        result = self.parse('---')
-        expected = '---' # inside <p>
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testStandardRule(self):
-        """ parser.wiki: ---- is standard rule """
-        py.test.skip("Broken because of line numbers")
-        result = self.parse('----')
-        expected = '<hr>'
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testVariableRule(self):
-        """ parser.wiki: ----- rules with size """
-        py.test.skip("Broken because of line numbers")
-
-        for size in range(5, 11):
-            test = '-' * size         
-            result = self.parse(test)
-            expected = '<hr class="hr%d">' % (size - 4)
-            self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testLongRule(self):
-        """ parser.wiki: ------------ long rule shortened to hr6 """
-        py.test.skip("Broken because of line numbers")
-        test = '-' * 254        
-        result = self.parse(test)
-        expected = '<hr class="hr6">'
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class TestBlock(ParserTestCase):
-    cases = (
-        # test, block start
-        ('----\n', '<hr'),
-        ('= Heading =\n', '<h2'),
-        ('{{{\nPre\n}}}\n', '<pre'),
-        ('{{{\n#!python\nPre\n}}}\n', '<div'),
-        ('|| Table ||', '<div'),
-        (' * unordered list\n', '<ul'),
-        (' 1. ordered list\n', '<ol'),
-        (' indented text\n', '<ul'),
-        )
-
-    def testParagraphBeforeBlock(self):
-        """ parser.wiki: paragraph closed before block element """
-        py.test.skip("Broken because of line numbers")
-        text = """AAA
-%s
-"""
-        for test, blockstart in self.cases:
-            # We dont test here formatter white space generation
-            expected = r'<p>AAA\s*</p>\n+%s' % blockstart
-            needle = re.compile(expected, re.MULTILINE)
-            result = self.parse(text % test)
-            match = needle.search(result)
-            self.assert_(match is not None,
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-            
-    def testEmptyLineBeforeBlock(self):
-        """ parser.wiki: empty lines before block element ignored
-        
-        Empty lines separate paragraphs, but should be ignored if a block
-        element follow.
-
-        Currently an empty paragraph is created, which make no sense but
-        no real harm.
-        """
-        py.test.skip("Broken because of line numbers")
-        text = """AAA
-
-%s
-"""
-        for test, blockstart in self.cases:
-            expected = r'<p>AAA\s*</p>\n+%s' % blockstart
-            needle = re.compile(expected, re.MULTILINE)
-            result = self.parse(text % test)
-            match = needle.search(result)
-            self.assert_(match is not None,
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testUrlAfterBlock(self):
-        """ parser.wiki: tests url after block element """
-        cases = ('some text {{{some block text\n}}} and a URL http://moinmo.in/',
-                 'some text {{{some block text\n}}} and a WikiName')
-
-        for case in cases:          
-            result = self.parse(case).strip()
-            match = result.endswith('</a>')
-            expected = True
-            self.assert_(match is True,
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-
--- a/MoinMoin/_tests/test_request.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    MoinMoin - MoinMoin.module_tested Tests
-
-    Module names must start with 'test_' to be included in the tests.
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from MoinMoin import config, wikiutil
-
-class TestNormalizePagename(unittest.TestCase):
-
-    def testPageInvalidChars(self):
-        """ request: normalize pagename: remove invalid unicode chars
-
-        Assume the default setting
-        """
-        test = u'\u0000\u202a\u202b\u202c\u202d\u202e'
-        expected = u''
-        result = self.request.normalizePagename(test)
-        self.assertEqual(result, expected,
-                         ('Expected "%(expected)s" but got "%(result)s"') % locals())
-
-    def testNormalizeSlashes(self):
-        """ request: normalize pagename: normalize slashes """
-        cases = (
-            (u'/////', u''),
-            (u'/a', u'a'),
-            (u'a/', u'a'),
-            (u'a/////b/////c', u'a/b/c'),
-            (u'a b/////c d/////e f', u'a b/c d/e f'),
-            )
-        for test, expected in cases:
-            result = self.request.normalizePagename(test)
-            self.assertEqual(result, expected,
-                             ('Expected "%(expected)s" but got "%(result)s"') %
-                             locals())
-
-    def testNormalizeWhitespace(self):
-        """ request: normalize pagename: normalize whitespace """
-        cases = (
-            (u'         ', u''),
-            (u'    a', u'a'),
-            (u'a    ', u'a'),
-            (u'a     b     c', u'a b c'),
-            (u'a   b  /  c    d  /  e   f', u'a b/c d/e f'),
-            # All 30 unicode spaces
-            (config.chars_spaces, u''),
-            )
-        for test, expected in cases:
-            result = self.request.normalizePagename(test)
-            self.assertEqual(result, expected,
-                             ('Expected "%(expected)s" but got "%(result)s"') %
-                             locals())
-
-    def testUnderscoreTestCase(self):
-        """ request: normalize pagename: underscore convert to spaces and normalized
-
-        Underscores should convert to spaces, then spaces should be
-        normalized, order is important!
-        """
-        cases = (
-            (u'         ', u''),
-            (u'  a', u'a'),
-            (u'a  ', u'a'),
-            (u'a  b  c', u'a b c'),
-            (u'a  b  /  c  d  /  e  f', u'a b/c d/e f'),
-            )
-        for test, expected in cases:
-            result = self.request.normalizePagename(test)
-            self.assertEqual(result, expected,
-                             ('Expected "%(expected)s" but got "%(result)s"') %
-                             locals())
-
-
-class TestGroupPages(unittest.TestCase):
-
-    def setUp(self):
-        self.config = self.TestConfig(page_group_regex=r'.+Group')
-
-    def tearDown(self):
-        del self.config
-
-    def testNormalizeGroupName(self):
-        """ request: normalize pagename: restrict groups to alpha numeric Unicode
-        
-        Spaces should normalize after invalid chars removed!
-        """
-        import re
-        cases = (
-            # current acl chars
-            (u'Name,:Group', u'NameGroup'),
-            # remove than normalize spaces
-            (u'Name ! @ # $ % ^ & * ( ) + Group', u'Name Group'),
-            )
-        for test, expected in cases:
-            # validate we are testing valid group names
-            if wikiutil.isGroupPage(self.request, test):
-                result = self.request.normalizePagename(test)
-                self.assertEqual(result, expected,
-                                 ('Expected "%(expected)s" but got "%(result)s"') %
-                                 locals())
-
-
-class TestHTTPDate(unittest.TestCase):
-
-    def testRFC1123Date(self):
-        """ request: httpDate default rfc1123 """
-        self.failUnlessEqual(self.request.httpDate(0),
-                             'Thu, 01 Jan 1970 00:00:00 GMT',
-                             'wrong date string')
-
-    def testRFC850Date(self):
-        """ request: httpDate rfc850 """
-        self.failUnlessEqual(self.request.httpDate(0, rfc='850'),
-                             'Thursday, 01-Jan-70 00:00:00 GMT',
-                             'wrong date string')
-
-
--- a/MoinMoin/_tests/test_search.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.search Tests
-
-    @copyright: 2005 by Nir Soffer <nirs@freeshell.org>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from MoinMoin import search
-
-
-class TestQuotingBug(unittest.TestCase):
-    """search: quoting bug tests 
-    
-    http://moinmoin.wikiwikiweb.de/MoinMoinBugs/SearchOneCharString
-    
-    This is only a little stupid test for the isQuoted method, because
-    testing parsed queries is much more work.
-    """
-
-    def setUp(self):
-        self.parser = search.QueryParser()
-
-    def testIsQuoted(self):
-        """ search: quoting bug - quoted terms """
-        for case in ('"yes"', "'yes'"):
-            self.assertEqual(self.parser.isQuoted(case), True)
-
-    def testIsNot(self):
-        """ search: quoting bug - unquoted terms """
-        tests = ('', "'", '"', '""', "''", "'\"", '"no', 'no"', "'no",
-                 "no'", '"no\'')
-        for case in tests:
-            self.assertEqual(self.parser.isQuoted(case), False)
-
--- a/MoinMoin/_tests/test_security.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.security Tests
-
-    TODO: when refactoring this, do not use "iter" (is a builtin)
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-                2007 by MoinMoin:ReimarBauer
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import py
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from MoinMoin import security
-
-acliter = security.ACLStringIterator
-
-class TestACLStringIterator(unittest.TestCase):
-
-    def setUp(self):
-        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
-    def tearDown(self):
-        del self.config
-
-    def testEmpty(self):
-        """ security: empty acl string raise StopIteration """
-        iter = acliter(self.request.cfg.acl_rights_valid, '')
-        self.failUnlessRaises(StopIteration, iter.next)
-
-    def testWhiteSpace(self):
-        """ security: white space acl string raise StopIteration """
-        iter = acliter(self.request.cfg.acl_rights_valid, '       ')
-        self.failUnlessRaises(StopIteration, iter.next)
-
-    def testDefault(self):
-        """ security: default meta acl """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'Default Default')
-        for mod, entries, rights in iter:
-            self.assertEqual(entries, ['Default'])
-            self.assertEqual(rights, [])
-
-    def testEmptyRights(self):
-        """ security: empty rights """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['WikiName'])
-        self.assertEqual(rights, [])
-
-    def testSingleWikiNameSingleWrite(self):
-        """ security: single wiki name, single right """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:read')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['WikiName'])
-        self.assertEqual(rights, ['read'])
-
-    def testMultipleWikiNameAndRights(self):
-        """ security: multiple wiki names and rights """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,UserTwo:read,write')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne', 'UserTwo'])
-        self.assertEqual(rights, ['read', 'write'])
-
-    def testMultipleWikiNameAndRightsSpaces(self):
-        """ security: multiple names with spaces """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'user one,user two:read')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user one', 'user two'])
-        self.assertEqual(rights, ['read'])
-
-    def testMultipleEntries(self):
-        """ security: multiple entries """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write UserTwo:read All:')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne'])
-        self.assertEqual(rights, ['read', 'write'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserTwo'])
-        self.assertEqual(rights, ['read'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['All'])
-        self.assertEqual(rights, [])
-
-    def testNameWithSpaces(self):
-        """ security: single name with spaces """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user one'])
-        self.assertEqual(rights, ['read'])
-
-    def testMultipleEntriesWithSpaces(self):
-        """ security: multiple entries with spaces """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read,write user two:read')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user one'])
-        self.assertEqual(rights, ['read', 'write'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user two'])
-        self.assertEqual(rights, ['read'])
-
-    def testMixedNames(self):
-        """ security: mixed wiki names and names with spaces """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write user three,UserFour:read')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne', 'user two'])
-        self.assertEqual(rights, ['read', 'write'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user three', 'UserFour'])
-        self.assertEqual(rights, ['read'])
-
-    def testModifier(self):
-        """ security: acl modifiers """
-        iter = acliter(self.request.cfg.acl_rights_valid, '+UserOne:read -UserTwo:')
-        mod, entries, rights = iter.next()
-        self.assertEqual(mod, '+')
-        self.assertEqual(entries, ['UserOne'])
-        self.assertEqual(rights, ['read'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(mod, '-')
-        self.assertEqual(entries, ['UserTwo'])
-        self.assertEqual(rights, [])
-
-    def testIgnoreInvalidACL(self):
-        """ security: ignore invalid acl
-
-        The last part of this acl can not be parsed. If it ends with :
-        then it will be parsed as one name with spaces.
-        """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read user two is ignored')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne'])
-        self.assertEqual(rights, ['read'])
-        self.failUnlessRaises(StopIteration, iter.next)
-
-    def testEmptyNamesWithRight(self):
-        """ security: empty names with rights
-
-        The documents does not talk about this case, may() should ignore
-        the rights because there is no entry.
-        """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read :read All:')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne'])
-        self.assertEqual(rights, ['read'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, [])
-        self.assertEqual(rights, ['read'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['All'])
-        self.assertEqual(rights, [])
-
-    def testIgnodeInvalidRights(self):
-        """ security: ignore rights not in acl_rights_valid """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,sing,write,drink,sleep')
-        mod, entries, rights = iter.next()
-        self.assertEqual(rights, ['read', 'write'])
-
-    def testBadGuy(self):
-        """ security: bad guy may not allowed anything
-
-        This test was failing on the apply acl rights test.
-        """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write BadGuy: All:read')
-        mod, entries, rights = iter.next()
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['BadGuy'])
-        self.assertEqual(rights, [])
-
-    def testAllowExtraWhitespace(self):
-        """ security: allow extra white space between entries """
-        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write   user three,UserFour:read  All:')
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['UserOne', 'user two'])
-        self.assertEqual(rights, ['read', 'write'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['user three', 'UserFour'])
-        self.assertEqual(rights, ['read'])
-        mod, entries, rights = iter.next()
-        self.assertEqual(entries, ['All'])
-        self.assertEqual(rights, [])
-
-
-class TestAcl(unittest.TestCase):
-    """ security: testing access control list
-
-    TO DO: test unknown user?
-    """
-    def setUp(self):
-        # Backup user
-        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
-        self.savedUser = self.request.user.name
-
-    def tearDown(self):
-        # Restore user
-        self.request.user.name = self.savedUser
-        del self.config
-
-    def testApplyACLByUser(self):
-        """ security: applying acl by user name"""
-        # This acl string...
-        acl_rights = [
-            "Admin1,Admin2:read,write,delete,revert,admin  "
-            "Admin3:read,write,admin  "
-            "JoeDoe:read,write  "
-            "name with spaces,another one:read,write  "
-            "CamelCase,extended name:read,write  "
-            "BadGuy:  "
-            "All:read  "
-            ]
-        acl = security.AccessControlList(self.request.cfg, acl_rights)
-
-        # Should apply these rights:
-        users = (
-            # user,                 rights
-            # CamelCase names
-            ('Admin1',              ('read', 'write', 'admin', 'revert', 'delete')),
-            ('Admin2',              ('read', 'write', 'admin', 'revert', 'delete')),
-            ('Admin3',              ('read', 'write', 'admin')),
-            ('JoeDoe',              ('read', 'write')),
-            ('SomeGuy',             ('read',)),
-            # Extended names or mix of extended and CamelCase
-            ('name with spaces',    ('read','write',)),
-            ('another one',         ('read','write',)),
-            ('CamelCase',           ('read','write',)),
-            ('extended name',       ('read','write',)),
-            # Blocking bad guys
-            ('BadGuy',              ()),
-            # All other users - every one not mentioned in the acl lines
-            ('All',                 ('read',)),
-            ('Anonymous',           ('read',)),
-            )
-
-        # Check rights
-        for user, may in users:
-            mayNot = [right for right in self.request.cfg.acl_rights_valid
-                      if right not in may]
-            # User should have these rights...
-            for right in may:
-                self.assert_(acl.may(self.request, user, right),
-                    '"%(user)s" should be allowed to "%(right)s"' % locals())
-            # But NOT these:
-            for right in mayNot:
-                self.failIf(acl.may(self.request, user, right),
-                    '"%(user)s" should NOT be allowed to "%(right)s"' % locals())
-
-    def testACLsWithoutEditLogEntry(self):
-        """ tests what are the page rights if edit-log entry doesn't exist
-            for a page where no access is given to
-        """
-        py.test.skip("test tricks out the caching system, page modifications without making an edit-log entry are not supported")
-        import os
-        from MoinMoin.Page import Page
-        pagename = u'AutoCreatedMoinMoinTemporaryTestPage'
-
-        result = self.request.user.may.write(pagename)
-        page = Page(self.request, pagename)
-        path = page.getPagePath(use_underlay=0, check_create=0)
-        if os.path.exists(path):
-            py.test.skip("%s exists. Won't overwrite exiting page" % self.dictPage)
-
-        try:
-            try:
-                os.mkdir(path)
-                revisionsDir = os.path.join(path, 'revisions')
-                os.mkdir(revisionsDir)
-                current = '00000001'
-                file(os.path.join(path, 'current'), 'w').write('%s\n' % current)
-                text = u'#acl All: \n'
-                file(os.path.join(revisionsDir, current), 'w').write(text)
-            except Exception, err:
-                py.test.skip("Can not be create test page: %s" % err)
-    
-            assert not self.request.user.may.write(pagename)
-        finally:
-            if os.path.exists(path):
-                import shutil
-                shutil.rmtree(path, True)
-
--- a/MoinMoin/_tests/test_widget_html.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.widget.html Tests
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-from MoinMoin.widget import html
-
-class TestHTMLWidgets(unittest.TestCase):
-    """widget.html: testing html widgets"""
-
-    def testCreate(self):
-        """widget.html: creating html widgets
-
-        TO DO: add tests for all elements by HTML 4 spec.
-        """
-        tests = (
-            # description, call, expected           
-            ('Create text', html.Text('<br> &'), '&lt;br&gt; &amp;'),
-            ('Create raw html', html.Raw('<br> &amp;'), '<br> &amp;'),
-            ('Create br', html.BR(), '<br>'),
-            ('Create hr', html.HR(), '<hr>'),
-            ('Create p', html.P(), '<p></p>'),
-            )
-
-        for description, obj, expected in tests:
-            result = unicode(obj)
-            self.assertEqual(result, expected,
-                             ('%(description)s: expected "%(expected)s" '
-                              'but got "%(result)s"') % locals())
-
-    def testInvalidAttributes(self):
-        """widegt.html: invalid attributes raises exception
-
-        TO DO: add tests for all elements by HTML 4 spec.
-        """
-        self.assertRaises(AttributeError, html.BR, name='foo')
-
-
-    def testCompositeElements(self):
-        """widget.html: append to and extend composite element"""
-        html._SORT_ATTRS = 1
-        element = html.P()
-
-        actions = (
-            # action, data, expected
-            (element.append,
-             html.Text('Text & '),
-             '<p>Text &amp; </p>'),
-            (element.append,
-             html.Text('more text. '),
-             '<p>Text &amp; more text. </p>'),
-            (element.extend,
-             (html.Text('And then '), html.Text('some.')),
-             '<p>Text &amp; more text. And then some.</p>'),
-            )
-
-        for action, data, expected in actions:
-            action(data)
-            result = unicode(element)
-            self.assertEqual(result, expected,
-                             'Expected "%(expected)s" but got "%(result)s"' % locals())
-
--- a/MoinMoin/_tests/test_wikidicts.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/_tests/test_wikidicts.py	Mon Jul 02 13:15:50 2007 +0200
@@ -2,38 +2,39 @@
 """
     MoinMoin - MoinMoin.wikidicts tests
 
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>,
+                2007 by MoinMoin:ThomasWaldmann
     @license: GNU GPL, see COPYING for details.
 """
 
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+import py
 import re
 
 from MoinMoin import wikidicts
 from MoinMoin import Page
 
-class TestGroupPage(unittest.TestCase):
+class TestGroupPage:
 
     def testCamelCase(self):
         """ wikidicts: initFromText: CamelCase links """
         text = """
  * CamelCase
 """
-        self.assertEqual(self.getMembers(text), ['CamelCase'])
+        assert self.getMembers(text) == ['CamelCase']
 
     def testExtendedName(self):
         """ wikidicts: initFromText: extended names """
         text = """
  * extended name
 """
-        self.assertEqual(self.getMembers(text), ['extended name'])
+        assert self.getMembers(text) == ['extended name']
 
     def testExtendedLink(self):
         """ wikidicts: initFromText: extended link """
         text = """
  * ["extended link"]
 """
-        self.assertEqual(self.getMembers(text), ['extended link'])
+        assert self.getMembers(text) == ['extended link']
 
     def testIgnoreSecondLevelList(self):
         """ wikidicts: initFromText: ignore non first level items """
@@ -43,7 +44,7 @@
     * forth level
      * and then some...
 """
-        self.assertEqual(self.getMembers(text), [])
+        assert self.getMembers(text) == []
 
     def testIgnoreOther(self):
         """ wikidicts: initFromText: ignore anything but first level list itmes """
@@ -53,14 +54,14 @@
 
 Ignore previous line and this text.
 """
-        self.assertEqual(self.getMembers(text), ['take this'])
+        assert self.getMembers(text) == ['take this']
 
     def testStripWhitespace(self):
         """ wikidicts: initFromText: strip whitespace around items """
         text = """
  *   take this  
 """
-        self.assertEqual(self.getMembers(text), ['take this'])
+        assert self.getMembers(text) == ['take this']
 
     def getMembers(self, text):
         group = wikidicts.Group(self.request, '')
@@ -68,7 +69,7 @@
         return group.members()
 
 
-class TestDictPage(unittest.TestCase):
+class TestDictPage:
 
     def testGroupMembers(self):
         """ wikidicts: create dict from keys and values in text """
@@ -86,13 +87,13 @@
 '''
         d = wikidicts.Dict(self.request, '')
         d.initFromText(text)
-        self.assertEqual(d['First'], 'first item')
-        self.assertEqual(d['text with spaces'], 'second item')
-        self.assertEqual(d['Empty string'], '')
-        self.assertEqual(d['Last'], 'last item')
+        assert d['First'] == 'first item'
+        assert d['text with spaces'] == 'second item'
+        assert d['Empty string'] == ''
+        assert d['Last'] == 'last item'
+        assert len(d) == 4
 
-
-class GroupDictTestCase(unittest.TestCase):
+class TestGroupDicts:
 
     def testSystemPagesGroupInDicts(self):
         """ wikidict: names in SystemPagesGroup should be in request.dicts
@@ -101,10 +102,16 @@
 
         Assume that the SystemPagesGroup is in the data or the underlay dir.
         """
-        assert Page.Page(self.request, 'SystemPagesGroup').exists(), \
-               "SystemPagesGroup is missing, Can't run test"
+        assert Page.Page(self.request, 'SystemPagesGroup').exists(), "SystemPagesGroup is missing, Can't run test"
         systemPages = wikidicts.Group(self.request, 'SystemPagesGroup')
+        #print repr(systemPages)
+        #print repr(self.request.dicts['SystemPagesGroup'])
         for member in systemPages.members():
-            self.assert_(self.request.dicts.has_member('SystemPagesGroup', member),
-                         '%s should be in request.dict' % member)
+            assert self.request.dicts.has_member('SystemPagesGroup', member), '%s should be in request.dict' % member
 
+        members, groups = self.request.dicts.expand_group('SystemPagesGroup')
+        assert 'SystemPagesInEnglishGroup' in groups
+        assert 'RecentChanges' in members
+        assert 'HelpContents' in members
+
+
--- a/MoinMoin/_tests/test_wikiutil.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/_tests/test_wikiutil.py	Mon Jul 02 13:15:50 2007 +0200
@@ -11,6 +11,96 @@
 from MoinMoin import wikiutil
 
 
+class TestQueryStringSupport:
+    tests = [
+        ('', {}, {}),
+        ('key1=value1', {'key1': 'value1'}, {'key1': u'value1'}),
+        ('key1=value1&key2=value2', {'key1': 'value1', 'key2': 'value2'}, {'key1': u'value1', 'key2': u'value2'}),
+        ('rc_de=Aktuelle%C3%84nderungen', {'rc_de': 'Aktuelle\xc3\x84nderungen'}, {'rc_de': u'Aktuelle\xc4nderungen'}),
+    ]
+    def testParseQueryString(self):
+        for qstr, expected_str, expected_unicode in self.tests:
+            assert wikiutil.parseQueryString(qstr, want_unicode=False) == expected_str
+            assert wikiutil.parseQueryString(qstr, want_unicode=True) == expected_unicode
+            assert wikiutil.parseQueryString(unicode(qstr), want_unicode=False) == expected_str
+            assert wikiutil.parseQueryString(unicode(qstr), want_unicode=True) == expected_unicode
+
+    def testMakeQueryString(self):
+        for qstr, in_str, in_unicode in self.tests:
+            assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_unicode, want_unicode=False), want_unicode=False) == in_str
+            assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_str, want_unicode=False), want_unicode=False) == in_str
+            assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_unicode, want_unicode=True), want_unicode=True) == in_unicode
+            assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_str, want_unicode=True), want_unicode=True) == in_unicode
+
+
+class TestTickets:
+    def testTickets(self):
+        from MoinMoin.Page import Page
+        # page name with double quotes
+        self.request.page = Page(self.request, u'bla"bla')
+        ticket1 = wikiutil.createTicket(self.request)
+        assert wikiutil.checkTicket(self.request, ticket1)
+        # page name with non-ASCII chars
+        self.request.page = Page(self.request, u'\xc4rger')
+        ticket2 = wikiutil.createTicket(self.request)
+        assert wikiutil.checkTicket(self.request, ticket2)
+        # same page with another action
+        self.request.page = Page(self.request, u'\xc4rger')
+        self.request.action = 'another'
+        ticket3 = wikiutil.createTicket(self.request)
+        assert wikiutil.checkTicket(self.request, ticket3)
+
+        assert ticket1 != ticket2
+        assert ticket2 != ticket3
+
+
+class TestCleanInput:
+    def testCleanInput(self):
+        tests = [(u"", u""), # empty
+                 (u"aaa\r\n\tbbb", u"aaa   bbb"), # ws chars -> blanks
+                 (u"aaa\x00\x01bbb", u"aaabbb"), # strip weird chars
+                 (u"a"*500, u""), # too long
+                ]
+        for instr, outstr in tests:
+            assert wikiutil.clean_input(instr) == outstr
+
+
+class TestNameQuoting:
+    tests = [(u"", u"''"), # empty
+             (u"test", u"'test'"), # nothing special
+             (u"Sarah O'Connor", u"\"Sarah O'Connor\""), # contains ', quote with "
+             (u'Just "something" quoted', u'\'Just "something" quoted\''), # contains ", quote with '
+            ]
+    def testQuoteName(self):
+        for name, qname in self.tests:
+            assert wikiutil.quoteName(name) == qname
+
+    def testUnquoteName(self):
+        for name, qname in self.tests:
+            assert wikiutil.unquoteName(qname) == name
+
+
+class TestInterWiki:
+    def testSplitWiki(self):
+        tests = [('SomePage', ('Self', 'SomePage', '')),
+                 ('OtherWiki:OtherPage', ('OtherWiki', 'OtherPage', '')),
+                 ('MoinMoin:"Page with blanks" link title', ("MoinMoin", "Page with blanks", "link title")),
+                 ("MoinMoin:'Page with blanks' link title", ("MoinMoin", "Page with blanks", "link title")),
+                 ('attachment:"filename with blanks.txt" other title', ("attachment", "filename with blanks.txt", "other title")),
+                ]
+        for markup, (wikiname, pagename, linktext) in tests:
+            assert wikiutil.split_wiki(markup) == (wikiname, pagename, linktext)
+
+    def testJoinWiki(self):
+        tests = [(('http://example.org/', u'SomePage'), 'http://example.org/SomePage'),
+                 (('http://example.org/?page=$PAGE&action=show', u'SomePage'), 'http://example.org/?page=SomePage&action=show'),
+                 (('http://example.org/', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen'),
+                 (('http://example.org/$PAGE/show', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen/show'),
+                ]
+        for (baseurl, pagename), url in tests:
+            assert wikiutil.join_wiki(baseurl, pagename) == url
+
+
 class TestSystemPagesGroup:
     def testSystemPagesGroupNotEmpty(self):
         assert self.request.dicts.members('SystemPagesGroup')
--- a/MoinMoin/_tests/test_wikixml_marshal.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.wikixml.marshal Tests
-
-    @copyright: 2002-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
-import array
-from MoinMoin.wikixml import marshal
-
-class TestMarshal(unittest.TestCase):
-    """Testing Marshal used for ...XXX"""
-
-    class Data:
-        cvar = 'Class Variable'
-        def __init__(self, value):
-            self.ivar = value
-
-    prop = (
-        # value, xml representation in a marshal object
-        (None, '<data><prop><none/></prop></data>'),
-        ("string", '<data><prop>string</prop></data>'),
-        ([1, "abc"], '<data><prop><item>1</item><item>abc</item></prop></data>'),
-        ((1, "abc"), '<data><prop><item>1</item><item>abc</item></prop></data>'),
-        ({"abc": 1}, '<data><prop><abc>1</abc></prop></data>'),
-        (1, '<data><prop>1</prop></data>'),
-        (Data('value'), '<data><prop><data><ivar>value</ivar></data></prop></data>'),
-        (array.array("i", [42]), "<data><prop>array('i', [42])</prop></data>"),
-        (buffer("0123456789", 2, 3), "<data><prop>234</prop></data>"),
-        )
-
-    def setUp(self):
-        self.obj = marshal.Marshal()
-
-    def testCreateMarshal(self):
-        """wikixml.marshal: create new marshal"""
-        self._checkData(self.obj, '<data></data>')
-
-    def testSetMarshalProperty(self):
-        """wikixml.marshal: setting marshal property"""
-        for value, xml in self.prop:
-            self.obj.prop = value
-            self._checkData(self.obj, xml)
-
-    def _canonize(self, xml):
-        xml = xml.replace('\n', '')
-        return xml
-
-    def _checkData(self, obj, xml):
-        objXML = self._canonize(obj.toXML())
-        expected = self._canonize(xml)
-        self.assertEqual(objXML, expected,
-            'Expected "%(expected)s" but got "%(objXML)s"' % locals())
-
--- a/MoinMoin/_tests/test_xmlrpc_multicall.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.xmlrpc.xmlrpc_system_multicall Fault serialization
-
-    @copyright: 2007 by Karol Nowak <grywacz@gmail.com>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-from MoinMoin.xmlrpc import XmlRpcBase
-from xmlrpclib import Fault
-
-def xmlrpc_return_fault():
-    return Fault(666, "Fault description")
-
-def test_fault_serialization(request):
-    xmlrpc = XmlRpcBase(request)
-    xmlrpc.xmlrpc_return_fault = xmlrpc_return_fault
-    args = [{'methodName': 'return_fault', 'params': [ ]}]
-    
-    print """If a XML RPC method returns a Fault, we should get a failure response
-    instead of a serialized Fault, as it happened in the past. See revision
-    8b7d6d70fc95 for details"""
-    
-    result = xmlrpc.xmlrpc_system_multicall(args)
-    assert type(result[0]) == dict
-    assert result[0].has_key("faultCode") and result[0].has_key("faultString")
--- a/MoinMoin/action/SyncPages.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/action/SyncPages.py	Mon Jul 02 13:15:50 2007 +0200
@@ -107,7 +107,7 @@
             "password": None,
         }
 
-        options.update(Dict(self.request, self.pagename).get_dict())
+        options.update(Dict(self.request, self.pagename))
 
         # Convert page and group list strings to lists
         if options["pageList"] is not None:
--- a/MoinMoin/config/__init__.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/config/__init__.py	Mon Jul 02 13:15:50 2007 +0200
@@ -34,6 +34,9 @@
 # benefit for the user. IMPORTANT: use only lowercase 'utf-8'!
 charset = 'utf-8'
 
+# Regex to find lower->upper transitions (word boundaries in WikiNames), used by split_title
+split_regex = re.compile('([%s])([%s])' % (chars_lower, chars_upper), re.UNICODE)
+
 # Invalid characters - invisible characters that should not be in page
 # names. Prevent user confusion and wiki abuse, e.g u'\u202aFrontPage'.
 page_invalid_chars_regex = re.compile(
--- a/MoinMoin/conftest.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/conftest.py	Mon Jul 02 13:15:50 2007 +0200
@@ -4,17 +4,16 @@
 --------------------------
 
 All test modules must be named test_modulename to be included in the
-test suit. If you are testing a package, name the test module
+test suite. If you are testing a package, name the test module
 test_package_module.
 
 Tests that need the current request, for example to create a page
 instance, can refer to self.request. It is injected into all test case
 classes by the framework.
 
-Tests that require certain configuration, like section_numbers = 1, must
-use a TestConfig to create the required configuration before the
-test. Deleting the TestConfig instance will restore the previous
-configuration.
+Tests that require a certain configuration, like section_numbers = 1, must
+use a TestConfig to create the required configuration before the test.
+Deleting the TestConfig instance will restore the previous configuration.
 
 @copyright: 2005 Nir Soffer, 2007 Alexander Schremmer
 @license: GNU GPL, see COPYING for details.
@@ -89,8 +88,8 @@
 class TestConfig:
     """ Custom configuration for unit tests
     
-    Some test assume specific configuration, and will fail if the wiki admin
-    will change the configuration. For example, DateTime macro test assume 
+    Some tests assume a specific configuration, and will fail if the wiki admin
+    changed the configuration. For example, DateTime macro test assume 
     the default datetime_fmt.
     
     When you set custom values in a TestConfig, the previous values are saved,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/converter/_tests/test_text_html_text_moin_wiki.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,1136 @@
+# -*- coding: utf-8 -*-
+"""
+MoinMoin - MoinMoin.text_html_text_moin_wiki Tests
+
+@copyright: 2005 by Bastian Blank, ThomasWaldmann
+@license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+
+import py
+py.test.skip("Many broken tests, much broken code, broken, broken, broken.")
+
+from cStringIO import StringIO
+from MoinMoin.converter import text_html_text_moin_wiki as converter
+from MoinMoin.parser.text_moin_wiki import Parser
+from MoinMoin.formatter.text_gedit import Formatter
+from MoinMoin.request import Clock
+from MoinMoin.error import ConvertError
+
+convert = converter.convert
+error = ConvertError
+
+
+class TestBase(unittest.TestCase):
+
+    def setUp(self):
+        self.cfg = self.TestConfig(bang_meta=True)
+        
+    def tearDown(self):
+        del self.cfg
+
+    def do_convert_real(self, func_args, successful=True):
+        try:
+            ret = convert(*func_args)
+        except error, e:
+            if successful:
+                self.fail("fails with parse error: %s" % e)
+            else:
+                return
+        if successful:
+            return ret
+        else:
+            self.fail("doesn't fail with parse error")
+
+
+class MinimalPage(object):
+    def __init__(self):
+        self.hilite_re = None
+        self.page_name = "testpage"
+
+
+class MinimalRequest(object):
+    # TODO: do we really need this class? no other test uses a request replacement.
+
+    def __init__(self, request):
+        self.request = request
+        self.clock = Clock()
+        
+        # This is broken - tests that need correct content_lang will fail
+        self.content_lang = None
+        self.current_lang = None
+        
+        self.form = {}
+        self._page_headings = {}
+        self.result = []
+
+    def getText(self, text, formatted=True):
+        return text
+
+    def write(self, text):
+        self.result.append(text)
+
+    def __getattr__(self, name):
+        return getattr(self.request, name)
+
+
+class TestConvertBlockRepeatable(TestBase):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        self.failUnlessEqual(text, out)
+
+    def testComment01(self):
+        test = ur"""
+##test
+"""
+        output = u"""<pre class="comment">\n##test</pre>"""
+        self.do(test, output)
+
+    def testComment02(self):
+        test = ur"""
+##test
+##test
+"""
+        output = u"""
+<pre class="comment">\n##test</pre>
+<pre class="comment">\n##test</pre>
+"""
+        self.do(test, output)
+
+    def testHeading01(self):
+        test = ur"""
+= test1 =
+
+"""
+        output = ur"""
+<h2>test1</h2>
+"""
+        self.do(test, output)
+
+    def testHeading02(self):
+        test = ur"""
+= test1 =
+
+== test2 ==
+
+"""
+        output = ur"""
+<h2>test1</h2>
+<h3>test2</h3>
+"""
+        self.do(test, output)
+
+    def testListSuccess01(self):
+        test = ur"""
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess02(self):
+        test = ur"""
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess03(self):
+        test = ur"""
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess04(self):
+        test = ur"""
+ * test
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess05(self):
+        test = ur"""
+ 1. test
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess06(self):
+        test = ur"""
+ test:: test
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess07(self):
+        test = ur"""
+ * test
+  
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess08(self):
+        test = ur"""
+ 1. test
+  
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess09(self):
+        test = ur"""
+ test:: test
+  
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess10(self):
+        test = ur"""
+ * test
+  * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess11(self):
+        test = ur"""
+ 1. test
+  1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess12(self):
+        test = ur"""
+ test:: test
+  test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess13(self):
+        test = ur"""
+ * test
+  * test
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess14(self):
+        test = ur"""
+ 1. test
+  1. test
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+</li>
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess15(self):
+        test = ur"""
+ test:: test
+  test:: test
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+</dd>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess16(self):
+        test = ur"""
+ * test
+
+ 1. test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess17(self):
+        test = ur"""
+ * test
+
+ test:: test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess18(self):
+        test = ur"""
+ 1. test
+
+ * test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess19(self):
+        test = ur"""
+ 1. test
+
+ test:: test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess20(self):
+        test = ur"""
+ test:: test
+
+ * test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess21(self):
+        test = ur"""
+ test:: test
+
+ 1. test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess23(self):
+        test = ur"""
+ 1. test
+  * test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess26(self):
+        test = ur"""
+ * test
+
+test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testListSuccess28(self):
+        test = ur"""
+ * test
+
+ test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess29(self):
+        test = ur"""
+ * test
+  * test
+ test
+"""
+        output = ur"""
+"""
+        self.do(test, output)
+
+    def testListSuccess30(self):
+        test = ur"""
+ * test
+  * test
+  test
+"""
+        output = ur"""
+"""
+        self.do(test, output)
+
+    def testParagraph1(self):
+        test = ur"""
+test
+
+"""
+        output = ur"""
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testParagraph2(self):
+        test = ur"""
+test
+
+test
+
+"""
+        output = ur"""
+<p>test </p>
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testPreSuccess1(self):
+        test = ur"""
+{{{
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess2(self):
+        test = ur"""
+{{{
+test
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess3(self):
+        test = ur"""
+{{{
+test
+
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess4(self):
+        test = ur"""
+{{{
+ * test
+}}}
+
+"""
+        output = ur"""
+<pre>
+ * test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess5(self):
+        test = ur"""
+{{{
+  }}}
+
+"""
+        output = ur"""
+<pre>
+  </pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess6(self):
+        test = ur"""
+ * {{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+test
+</pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess7(self):
+        test = ur"""
+ * {{{
+   test
+   }}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+   test
+   </pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess8(self):
+        test = ur"""
+ * test
+ {{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li><p>test 
+</p>
+<pre>
+test
+</pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess9(self):
+        test = ur"""
+ * test
+
+{{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+
+<pre>
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testRule1(self):
+        test = ur"""
+----
+
+"""
+        output = ur"""
+<hr/>
+"""
+        self.do(test, output)
+
+    def testTable01(self):
+        test = ur"""
+|| ||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p> </p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable02(self):
+        test = ur"""
+||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable03(self):
+        test = ur"""
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable04(self):
+        test = ur"""
+||test||
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable05(self):
+        test = ur"""
+||||test||
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable06(self):
+        test = ur"""
+||||test||test||
+||test||||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+class TestConvertInlineFormatRepeatable(TestBase):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        output = "<p>%s </p>" % output
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        out = out.rstrip('\n')
+        self.failUnlessEqual(text, out)
+
+    def testEmphasis01(self):
+        test = ur"''test''"
+        output = ur"<em>test</em>"
+        self.do(test, output)
+
+    def testEmphasis02(self):
+        test = ur"'''test'''"
+        output = ur"<strong>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis03(self):
+        test = ur"'''''test'''''"
+        output = ur"<em><strong>test</strong></em>"
+        self.do(test, output)
+
+    def testEmphasis04(self):
+        test = ur"''test'''test'''''"
+        output = ur"<em>test<strong>test</strong></em>"
+        self.do(test, output)
+
+    def testEmphasis05(self):
+        test = ur"'''test''test'''''"
+        output = ur"<strong>test<em>test</em></strong>"
+        self.do(test, output)
+
+    def testEmphasis06(self):
+        test = ur"''test'''test'''test''"
+        output = ur"<em>test<strong>test</strong>test</em>"
+        self.do(test, output)
+
+    def testEmphasis07(self):
+        test = ur"'''test''test''test'''"
+        output = ur"<strong>test<em>test</em>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis08(self):
+        test = ur"''test'''''test'''"
+        output = ur"<em>test</em><strong>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis09(self):
+        test = ur"'''test'''''test''"
+        output = ur"<strong>test</strong><em>test</em>"
+        self.do(test, output)
+
+    def testEmphasis10(self):
+        test = ur"'''''test''test'''"
+        output = ur"<strong><em>test</em>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis11(self):
+        test = ur"'''''test'''test''"
+        output = ur"<em><strong>test</strong>test</em>"
+        self.do(test, output)
+
+    def testFormatBig01(self):
+        test = ur"~+test+~"
+        output = ur"<big>test</big>"
+        self.do(test, output)
+
+    def testFormatSmall01(self):
+        test = ur"~-test-~"
+        output = ur"<small>test</small>"
+        self.do(test, output)
+
+    def testFormatStrike01(self):
+        test = ur"--(test)--"
+        output = ur"<strike>test</strike>"
+        self.do(test, output)
+
+    def testFormatSub01(self):
+        test = ur",,test,,"
+        output = ur"<sub>test</sub>"
+        self.do(test, output)
+
+    def testFormatSup01(self):
+        test = ur"^test^"
+        output = ur"<sup>test</sup>"
+        self.do(test, output)
+
+    def testFormatUnderline01(self):
+        test = ur"__test__"
+        output = ur"<u>test</u>"
+        self.do(test, output)
+
+    def testPre01(self):
+        test = ur"{{{test}}}"
+        output = ur"<tt>test</tt>"
+        self.do(test, output)
+
+    def testWhitespace01(self):
+        test = ur"''test '''test'''''"
+        output = ur"<em>test <strong>test</strong></em>"
+        self.do(test, output)
+
+class TestConvertInlineItemRepeatable(TestBase):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        output = "<p>%s </p>" % output
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        out = out.rstrip('\n')
+        self.failUnlessEqual(text, out)
+
+    def testWikiWord01(self):
+        test = ur"WikiWord"
+        output = ur"""<a class="nonexistent" href="./WikiWord">WikiWord</a>"""
+        self.do(test, output)
+
+    def testNoWikiWord01(self):
+        test = ur"!WikiWord"
+        output = ur"WikiWord"
+        self.do(test, output)
+
+    def testSmiley01(self):
+        test = ur":-)"
+        output = ur"""<img src="/wiki/modern/img/smile.png" alt=":-)" height="15" width="15">"""
+        self.do(test, output)
+
+class TestStrip(unittest.TestCase):
+    def do(self, cls, text, output):
+        tree = converter.parse(text)
+        cls().do(tree)
+        out = StringIO()
+        try:
+            import xml.dom.ext
+        except ImportError:
+            py.test.skip('xml.dom.ext module is not available')
+        xml.dom.ext.Print(tree, out)
+        self.failUnlessEqual("<?xml version='1.0' encoding='UTF-8'?>%s" % output, out.getvalue().decode("utf-8"))
+
+class TestStripWhitespace(TestStrip):
+    def do(self, text, output):
+        super(TestStripWhitespace, self).do(converter.strip_whitespace, text, output)
+
+    def test1(self):
+        test = ur"""
+<t/>
+"""
+        output = ur"""<t/>"""
+        self.do(test, output)
+
+    def test2(self):
+        test = ur"""
+<t>
+  <z/>
+</t>
+"""
+        output = ur"""<t><z/></t>"""
+        self.do(test, output)
+
+    def test3(self):
+        test = ur"""
+<t>
+  <z>test</z>
+</t>
+"""
+        output = ur"""<t><z>test</z></t>"""
+        self.do(test, output)
+
+    def test4(self):
+        test = ur"""<p>&nbsp;</p>"""
+        output = ur""""""
+        self.do(test, output)
+
+    def test5(self):
+        test = ur"""<p>test </p>"""
+        output = ur"""<p>test</p>"""
+        self.do(test, output)
+
+class TestConvertBrokenBrowser(TestBase):
+    def do(self, text, output):
+        text = text.strip('\n')
+        output = output.lstrip('\n')
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        out = self.do_convert_real([request, page.page_name, text])
+        self.failUnlessEqual(output, out)
+
+    def testList01(self):
+        test = ur"""
+<ul>
+<li>test</li>
+<ul>
+<li>test</li>
+</ul>
+<li>test</li>
+</ul>
+"""
+        output = ur"""
+ * test
+  * test
+ * test
+
+"""
+        self.do(test, output)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/events/wikidictsrescan.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,35 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - wikidicts notification plugin for event system
+
+    When a Group or Dict page changes, we rescan them and recreate the cache.
+
+    @copyright: 2007 by MoinMoin:ThomasWaldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+import logging
+
+from MoinMoin import events as ev
+from MoinMoin import wikidicts
+
+def handle(event):
+    if isinstance(event, ev.PageChangedEvent): # "changed" includes creation and deletion
+        cfg = event.request.cfg
+        pagename = event.page.page_name
+        if cfg.cache.page_dict_regex.search(pagename) or \
+           cfg.cache.page_group_regex.search(pagename):
+            return handle_groupsdicts_changed(event)
+    
+
+def handle_groupsdicts_changed(event):
+    """ Handles events related to groups and dicts page changes:
+        Scans all pages matching the dict / group regex and pickles the
+        data to disk.
+    """    
+    request = event.request
+    page = event.page
+    
+    logging.debug("groupsdicts changed: %r, scan_dicts started", page.page_name)
+    gd = wikidicts.GroupDict(request)
+    gd.scan_dicts()
+    logging.debug("groupsdicts changed: scan_dicts finished")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/formatter/_tests/test_formatter.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,78 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.formatter.* Tests
+
+    @copyright: 2005 by MoinMoin:AlexanderSchremmer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import py
+
+import re
+
+from MoinMoin.Page import Page
+from MoinMoin import wikiutil
+
+
+class TestFormatter:
+    def testSyntaxReferenceDomXml(self):
+        py.test.skip("dom_xml formatter is known to be broken")
+        f_name = 'dom_xml'
+        try:
+            formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
+        except wikiutil.PluginAttributeError:
+            pass
+        else:
+            print "Formatting using %r" % formatter
+            self.formatPage("SyntaxReference", formatter)
+            print "Done."
+
+    def testSyntaxReferenceDocBook(self):
+        py.test.skip("breaks with an attribute error, it should be checked whether the formatter on the DB branch is broken as well")
+        try:
+            from xml.dom import getDOMImplementation
+            dom = getDOMImplementation("4DOM")
+        except ImportError:
+            # if we don't have 4suite installed, the docbook formatter would just raise an exception
+            py.test.skip("not testing docbook formatter because no 4suite installed")
+        else:
+            f_name = 'text_docbook'
+            try:
+                formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
+            except wikiutil.PluginAttributeError:
+                pass
+            else:
+                print "Formatting using %r" % formatter
+                self.formatPage("SyntaxReference", formatter)
+                print "Done."
+
+    def testSyntaxReferenceOthers(self):
+        formatters = wikiutil.getPlugins("formatter", self.request.cfg)
+
+        # we have separate tests for those:
+        formatters.remove('text_docbook')
+        formatters.remove('dom_xml')
+
+        for f_name in formatters:
+            try:
+                formatter = wikiutil.importPlugin(self.request.cfg, "formatter", f_name, "Formatter")
+            except wikiutil.PluginAttributeError:
+                pass
+            else:
+                print "Formatting using %r" % formatter
+                self.formatPage("SyntaxReference", formatter)
+                print "Done."
+
+    def formatPage(self, pagename, formatter):
+        """Parse a page. Should not raise an exception if the API of the
+        formatter is correct.
+        """
+
+        self.request.reset()
+        page = Page(self.request, pagename, formatter=formatter)
+        self.request.formatter = page.formatter = formatter(self.request)
+        #page.formatter.setPage(page)
+        #page.hilite_re = None
+
+        return self.request.redirectedOutput(page.send_page, content_only=1)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/macro/_tests/test_Action.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+"""
+    MoinMoin - MoinMoin.macro.Action Tests
+
+    @copyright: 2007 MoinMoin:ReimarBauer
+
+    @license: GNU GPL, see COPYING for details.
+"""
+import os
+from MoinMoin import macro
+from MoinMoin.macro import Action
+from MoinMoin.Page import Page
+from MoinMoin.PageEditor import PageEditor
+
+
+class TestAction:
+    """ testing macro Action calling action raw """
+
+    def setup_class(self):
+        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForAction'
+        self.page = PageEditor(self.request, self.pagename)
+        self.shouldDeleteTestPage = True
+
+    def teardown_class(self):
+        if self.shouldDeleteTestPage:
+            import shutil
+            page = Page(self.request, self.pagename)
+            fpath = page.getPagePath(use_underlay=0, check_create=0)
+            shutil.rmtree(fpath, True)
+
+            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
+            if os.path.exists(fpath):
+                os.remove(fpath)
+
+    def _make_macro(self):
+        """Test helper"""
+        from MoinMoin.parser.text import Parser
+        from MoinMoin.formatter.text_html import Formatter
+        p = Parser("##\n", self.request)
+        p.formatter = Formatter(self.request)
+        p.formatter.page = self.page
+        self.request.formatter = p.formatter
+        p.form = self.request.form
+        m = macro.Macro(p)
+        return m
+
+    def _createTestPage(self, body):
+        """ Create temporary page """
+        assert body is not None
+        self.request.reset()
+        self.page.saveText(body, 0)
+
+    def testActionCallingRaw(self):
+        """ module_tested: executes raw by macro Action on existing page"""
+
+        expected = '<a href="./AutoCreatedMoinMoinTemporaryTestPageForAction?action=raw">raw</a>'
+        text = '= title1 =\n||A||B||\n'
+        self._createTestPage(text)
+        m = self._make_macro()
+        result = Action.execute(m, 'raw')
+
+        assert result == expected
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/macro/_tests/test_Hits.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,107 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.macro Hits tested
+
+    @copyright: 2007 MoinMoin:ReimarBauer
+
+    @license: GNU GPL, see COPYING for details.
+"""
+import os
+from MoinMoin import macro
+from MoinMoin.logfile import eventlog
+from MoinMoin.Page import Page
+from MoinMoin.PageEditor import PageEditor
+from MoinMoin.parser.text_moin_wiki import Parser
+
+class TestHits:
+    """Hits: testing Hits macro """
+
+    def setup_class(self):
+        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForHits'
+        self.page = PageEditor(self.request, self.pagename)
+        self.shouldDeleteTestPage = False
+        # for that test eventlog needs to be empty
+        fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
+        if os.path.exists(fpath):
+            os.remove(fpath)
+
+    def teardown_class(self):
+        if self.shouldDeleteTestPage:
+            import shutil
+            page = Page(self.request, self.pagename)
+            fpath = page.getPagePath(use_underlay=0, check_create=0)
+            shutil.rmtree(fpath, True)
+
+            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
+            if os.path.exists(fpath):
+                os.remove(fpath)
+
+    def _make_macro(self):
+        """Test helper"""
+        from MoinMoin.parser.text import Parser
+        from MoinMoin.formatter.text_html import Formatter
+        p = Parser("##\n", self.request)
+        p.formatter = Formatter(self.request)
+        p.formatter.page = self.page
+        self.request.formatter = p.formatter
+        p.form = self.request.form
+        m = macro.Macro(p)
+        return m
+
+    def _test_macro(self, name, args):
+        m = self._make_macro()
+        return m.execute(name, args)
+
+    def _createTestPage(self, body):
+        """ Create temporary page """
+        assert body is not None
+        self.request.reset()
+        self.page.saveText(body, 0)
+
+    def testHitsNoArg(self):
+        """ macro Hits test: 'no args for Hits (Hits is executed on current page) """
+        self.shouldDeleteTestPage = False
+        self._createTestPage('This is an example to test a macro')
+
+        # Three log entries for the current page and one for WikiSandBox simulating viewing
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': 'WikiSandBox'})
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
+
+        result = self._test_macro('Hits', '')
+        expected = "3"
+        assert result == expected
+
+    def testHitsForAll(self):
+        """ macro Hits test: 'all=1' for Hits (all pages are counted for VIEWPAGE) """
+        self.shouldDeleteTestPage = False
+        self._createTestPage('This is an example to test a macro with parameters')
+
+        # Two log entries for simulating viewing
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
+        eventlog.EventLog(self.request).add(self.request, 'VIEWPAGE', {'pagename': self.pagename})
+
+        result = self._test_macro('Hits', 'all=1')
+        expected = "6"
+        assert result == expected
+
+    def testHitsForFilter(self):
+        """ macro Hits test: 'all=1, filter=SAVEPAGE' for Hits (SAVEPAGE counted for current page)"""
+        self.shouldDeleteTestPage = False
+
+        # simulate a log entry SAVEPAGE for WikiSandBox to destinguish current page
+        eventlog.EventLog(self.request).add(self.request, 'SAVEPAGE', {'pagename': 'WikiSandBox'})
+        result = self._test_macro('Hits', 'filter=SAVEPAGE')
+        expected = "2"
+        assert result == expected
+
+    def testHitsForAllAndFilter(self):
+        """ macro test: 'all=1, filter=SAVEPAGE' for Hits (all pages are counted for SAVEPAGE)"""
+        self.shouldDeleteTestPage = True
+
+        result = self._test_macro('Hits', 'all=1, filter=SAVEPAGE')
+        expected = "3"
+        assert result == expected
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/macro/_tests/test_ImageLink.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,83 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.macro ImageLink tested
+
+    @copyright: 2007 MoinMoin:ReimarBauer
+
+    @license: GNU GPL, see COPYING for details.
+"""
+import os
+from MoinMoin import macro
+from MoinMoin.logfile import eventlog
+from MoinMoin.Page import Page
+from MoinMoin.PageEditor import PageEditor
+from MoinMoin.parser.text_moin_wiki import Parser
+
+class TestHits:
+    """Hits: testing Hits macro """
+
+    def setup_class(self):
+        self.pagename = u'AutoCreatedMoinMoinTemporaryTestPageForImageLink'
+        self.page = PageEditor(self.request, self.pagename)
+        self.shouldDeleteTestPage = False
+
+    def teardown_class(self):
+        if self.shouldDeleteTestPage:
+            import shutil
+            page = Page(self.request, self.pagename)
+            fpath = page.getPagePath(use_underlay=0, check_create=0)
+            shutil.rmtree(fpath, True)
+
+            fpath = self.request.rootpage.getPagePath('event-log', isfile=1)
+            if os.path.exists(fpath):
+                os.remove(fpath)
+
+    def _make_macro(self):
+        """Test helper"""
+        from MoinMoin.parser.text import Parser
+        from MoinMoin.formatter.text_html import Formatter
+        p = Parser("##\n", self.request)
+        p.formatter = Formatter(self.request)
+        p.formatter.page = self.page
+        self.request.formatter = p.formatter
+        p.form = self.request.form
+        m = macro.Macro(p)
+        return m
+
+    def _test_macro(self, name, args):
+        m = self._make_macro()
+        return m.execute(name, args)
+
+    def _createTestPage(self, body):
+        """ Create temporary page """
+        assert body is not None
+        self.request.reset()
+        self.page.saveText(body, 0)
+
+    def testImageLinkNoArg(self):
+        """ macro ImageLink test: 'no args for ImageLink (ImageLink is executed on FrontPage) """
+        #self._createTestPage('This is an example to test a macro')
+        result = self._test_macro('ImageLink', '')
+        expected = '<div class="message">Not enough arguments to ImageLink macro! e.g. [[ImageLink(example.png, WikiName, width=200)]].</div>'
+        assert result == expected
+
+    def testImageLinkTwoParamsNoKeyword(self):
+        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, FrontPage)]] """
+        self.shouldDeleteTestPage = False
+
+        result = self._test_macro('ImageLink', 'http://static.wikiwikiweb.de/logos/moindude.png, FrontPage')
+        expected = '<a href="./FrontPage"><img alt="FrontPage" src="http://static.wikiwikiweb.de/logos/moindude.png" title="FrontPage" /></a>'
+        assert result == expected
+
+    def testImageLinkTwoParamsOneKeyword(self):
+        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage)]] 
+        order of keywords to parameter list is independent 
+        """
+        self.shouldDeleteTestPage = True 
+
+        result = self._test_macro('ImageLink', 'http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage')
+        expected = '<a href="./FrontPage"><img alt="The old dude" src="http://static.wikiwikiweb.de/logos/moindude.png" title="The old dude" /></a>'
+        assert result == expected
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/macro/_tests/test_macro.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,34 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.macro Tests
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>,
+                2006 MoinMoin:ThomasWaldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+
+from MoinMoin import macro
+from MoinMoin.parser.text import Parser
+from MoinMoin.formatter.text_html import Formatter
+
+
+class TestMacro(unittest.TestCase):
+    def testTrivialMacro(self):
+        """macro: trivial macro works"""
+        m = self._make_macro()
+        expected = m.formatter.linebreak(0)
+        result = m.execute("BR", "")
+        self.assertEqual(result, expected,
+            'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def _make_macro(self):
+        """Test helper"""
+        p = Parser("##\n", self.request)
+        p.formatter = Formatter(self.request)
+        self.request.formatter = p.formatter
+        p.form = self.request.form
+        m = macro.Macro(p)
+        return m
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/mail/_tests/test_sendmail.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+"""
+    MoinMoin - MoinMoin.mail.sendmail Tests
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+from email.Charset import Charset, QP
+from email.Header import Header
+from MoinMoin.mail import sendmail
+from MoinMoin import config
+
+
+class TestdecodeSpamSafeEmail(unittest.TestCase):
+    """mail.sendmail: testing mail"""
+
+    _tests = (
+        ('', ''),
+        ('AT', '@'),
+        ('DOT', '.'),
+        ('DASH', '-'),
+        ('CAPS', ''),
+        ('Mixed', 'Mixed'),
+        ('lower', 'lower'),
+        ('Firstname DOT Lastname AT example DOT net',
+         'Firstname.Lastname@example.net'),
+        ('Firstname . Lastname AT exa mp le DOT n e t',
+         'Firstname.Lastname@example.net'),
+        ('Firstname I DONT WANT SPAM . Lastname@example DOT net',
+         'Firstname.Lastname@example.net'),
+        ('First name I Lastname DONT AT WANT SPAM example DOT n e t',
+         'FirstnameLastname@example.net'),
+        ('first.last@example.com', 'first.last@example.com'),
+        ('first . last @ example . com', 'first.last@example.com'),
+        )
+
+    def testDecodeSpamSafeMail(self):
+        """mail.sendmail: decoding spam safe mail"""
+        for coded, expected in self._tests:
+            result = sendmail.decodeSpamSafeEmail(coded)
+            self.assertEqual(result, expected,
+                             'Expected "%(expected)s" but got "%(result)s"' %
+                             locals())
+
+
+class TestEncodeAddress(unittest.TestCase):
+    """ Address encoding tests
+    
+    See http://www.faqs.org/rfcs/rfc2822.html section 3.4. 
+    Address Specification.
+            
+    mailbox     =   name-addr / addr-spec
+    name-addr   =   [display-name] angle-addr
+    angle-addr  =   [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+    """
+    charset = Charset(config.charset)
+    charset.header_encoding = QP
+    charset.body_encoding = QP
+
+    def testSimpleAddress(self):
+        """ mail.sendmail: encode simple address: local@domain """
+        address = u'local@domain'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testComposite(self):
+        """ mail.sendmail: encode address: 'Phrase <local@domain>' """
+        address = u'Phrase <local@domain>'
+        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
+        expected = phrase + '<local@domain>'
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testCompositeUnicode(self):
+        """ mail.sendmail: encode Uncode address: 'ויקי <local@domain>' """
+        address = u'ויקי <local@domain>'
+        phrase = str(Header(u'ויקי '.encode('utf-8'), self.charset))
+        expected = phrase + '<local@domain>'
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testEmptyPhrase(self):
+        """ mail.sendmail: encode address with empty phrase: '<local@domain>' """
+        address = u'<local@domain>'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testEmptyAddress(self):
+        """ mail.sendmail: encode address with empty address: 'Phrase <>' 
+        
+        Let the smtp server handle this. We may raise error in such
+        case, but we don't do error checking for mail addresses.
+        """
+        address = u'Phrase <>'
+        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
+        expected = phrase + '<>'
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testInvalidAddress(self):
+        """ mail.sendmail: encode invalid address 'Phrase <blah' 
+        
+        Assume that this is a simple address. This address will
+        probably cause an error when trying to send mail. Junk in, junk
+        out.
+        """
+        address = u'Phrase <blah'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(sendmail.encodeAddress(address, self.charset),
+                             expected)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/_tests/test_text_moin_wiki.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,566 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.parser.text_moin_wiki Tests
+
+    TODO: these are actually parser+formatter tests. We should have
+    parser only tests here.
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+import re
+from StringIO import StringIO
+
+import py
+
+from MoinMoin.Page import Page
+from MoinMoin.parser.text_moin_wiki import Parser
+
+
+class ParserTestCase(unittest.TestCase):
+    """ Helper class that provide a parsing method """
+
+    def parse(self, body):
+        """Parse body and return html
+
+        Create a page with body, then parse it and format using html formatter
+        """
+        assert body is not None
+        self.request.reset()
+        page = Page(self.request, 'ThisPageDoesNotExistsAndWillNeverBeReally')
+        page.set_raw_body(body)
+        from MoinMoin.formatter.text_html import Formatter
+        page.formatter = Formatter(self.request)
+        self.request.formatter = page.formatter
+        page.formatter.setPage(page)
+        page.hilite_re = None
+
+        output = StringIO()
+        saved_write = self.request.write
+        self.request.write = output.write
+        try:
+            Parser(body, self.request).format(page.formatter)
+        finally:
+            self.request.write = saved_write
+        return output.getvalue()
+
+
+class TestParagraphs(ParserTestCase):
+    """ Test paragraphs creating
+
+    All tests ignoring white space in output
+    """
+
+    def testFirstParagraph(self):
+        """ parser.wiki: first paragraph should be in <p> """
+        py.test.skip("Broken because of line numbers")
+        result = self.parse('First')
+        expected = re.compile(r'<p>\s*First\s*</p>')
+        self.assert_(expected.search(result),
+                      '"%s" not in "%s"' % (expected.pattern, result))
+
+    def testEmptyLineBetweenParagraphs(self):
+        """ parser.wiki: empty line separates paragraphs """
+        py.test.skip("Broken because of line numbers")
+        result = self.parse('First\n\nSecond')
+        expected = re.compile(r'<p>\s*Second\s*</p>')
+        self.assert_(expected.search(result),
+                     '"%s" not in "%s"' % (expected.pattern, result))
+
+    def testParagraphAfterBlockMarkup(self):
+        """ parser.wiki: create paragraph after block markup """
+        py.test.skip("Broken because of line numbers")
+
+        markup = (
+            '----\n',
+            '[[en]]\n',
+            '|| table ||\n',
+            '= heading 1 =\n',
+            '== heading 2 ==\n',
+            '=== heading 3 ===\n',
+            '==== heading 4 ====\n',
+            '===== heading 5 =====\n',
+            )
+        for item in markup:
+            text = item + 'Paragraph'
+            result = self.parse(text)
+            expected = re.compile(r'<p.*?>\s*Paragraph\s*</p>')
+            self.assert_(expected.search(result),
+                         '"%s" not in "%s"' % (expected.pattern, result))
+
+
+class TestHeadings(ParserTestCase):
+    """ Test various heading problems """
+
+    def setUp(self):
+        """ Require show_section_numbers = 0 to workaround counter
+        global state saved in request.
+        """
+        self.config = self.TestConfig(show_section_numbers=0)
+
+    def tearDown(self):
+        del self.config
+
+    def testIgnoreWhiteSpaceAroundHeadingText(self):
+        """ parser.wiki: ignore white space around heading text
+
+        See bug: TableOfContentsBreakOnExtraSpaces.
+
+        Does not test mapping of '=' to h number, or valid html markup.
+        """
+        py.test.skip("Broken because of line numbers")
+        tests = (
+            '=  head =\n', # leading
+            '= head  =\n', # trailing
+            '=  head  =\n' # both
+                 )
+        expected = self.parse('= head =')
+        for test in tests:
+            result = self.parse(test)
+            self.assertEqual(result, expected,
+                'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestTOC(ParserTestCase):
+
+    def setUp(self):
+        """ Require show_section_numbers = 0 to workaround counter
+        global state saved in request.
+        """
+        self.config = self.TestConfig(show_section_numbers=0)
+
+    def tearDown(self):
+        del self.config
+
+    def testHeadingWithWhiteSpace(self):
+        """ parser.wiki: TOC links to headings with white space
+        
+        See bug: TableOfContentsBreakOnExtraSpaces.
+
+        Does not test TOC or heading formating, just verify that spaces
+        around heading text does not matter.
+        """
+        standard = """
+[[TableOfContents]]
+= heading =
+Text
+"""
+        withWhitespace = """
+[[TableOfContents]]
+=   heading   =
+Text
+"""
+        expected = self.parse(standard)
+        result = self.parse(withWhitespace)
+        self.assertEqual(result, expected,
+            'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestDateTimeMacro(ParserTestCase):
+   """ Test DateTime macro
+
+   Might fail due to libc problems, therefore the fail message warn
+   about this.
+
+   TODO: when this test fail, does it mean that moin code fail on that
+   machine? - can we fix this?
+   """
+
+   text = 'AAA %s AAA'
+   needle = re.compile(text % r'(.+)')
+   _tests = (
+       # test                                   expected
+       ('[[DateTime(1970-01-06T00:00:00)]]',   '1970-01-06 00:00:00'),
+       ('[[DateTime(259200)]]',                '1970-01-04 00:00:00'),
+       ('[[DateTime(2003-03-03T03:03:03)]]',   '2003-03-03 03:03:03'),
+       ('[[DateTime(2000-01-01T00:00:00Z)]]',  '2000-01-01 00:00:00'),
+       ('[[Date(2002-02-02T01:02:03Z)]]',      '2002-02-02'),
+       )
+
+   def setUp(self):
+       """ Require default date and time format config values """
+       self.config = self.TestConfig(defaults=('date_fmt', 'datetime_fmt'))
+
+   def tearDown(self):
+       del self.config
+
+   def testDateTimeMacro(self):
+       """ parser.wiki: DateTime macro """
+       note = """
+   
+   If this fails, it is likely a problem in your python / libc,
+   not in moin.  See also:
+   <http://sourceforge.net/tracker/index.php?func=detail&
+       aid=902172&group_id=5470&atid=105470>"""
+
+       for test, expected in self._tests:
+           html = self.parse(self.text % test)
+           result = self.needle.search(html).group(1)
+           self.assertEqual(result, expected,
+               'Expected "%(expected)s" but got "%(result)s"; %(note)s' % locals())
+
+
+class TestTextFormatingTestCase(ParserTestCase):
+    """ Test wiki markup """
+
+    text = 'AAA %s AAA'
+    needle = re.compile(text % r'(.+)')
+    _tests = (
+        # test,                     expected
+        ('no format',               'no format'),
+        ("''em''",                  '<em>em</em>'),
+        ("'''bold'''",              '<strong>bold</strong>'),
+        ("__underline__",           '<span class="u">underline</span>'),
+        ("'''''Mix''' at start''",  '<em><strong>Mix</strong> at start</em>'),
+        ("'''''Mix'' at start'''",  '<strong><em>Mix</em> at start</strong>'),
+        ("'''Mix at ''end'''''",    '<strong>Mix at <em>end</em></strong>'),
+        ("''Mix at '''end'''''",    '<em>Mix at <strong>end</strong></em>'),
+        )
+
+    def testTextFormating(self):
+        """ parser.wiki: text formating """
+        for test, expected in self._tests:
+            html = self.parse(self.text % test)
+            result = self.needle.search(html).group(1)
+            self.assertEqual(result, expected,
+                             'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestCloseInlineTestCase(ParserTestCase):
+
+    def testCloseOneInline(self):
+        """ parser.wiki: close open inline tag when block close """
+        py.test.skip("Broken because of line numbers")
+        cases = (
+            # test, expected
+            ("text'''text\n", r"<p>text<strong>text\s*</strong></p>"),
+            ("text''text\n", r"<p>text<em>text\s*</em></p>"),
+            ("text__text\n", r"<p>text<span class=\"u\">text\s*</span></p>"),
+            ("text ''em '''em strong __em strong underline",
+             r"text <em>em <strong>em strong <span class=\"u\">em strong underline"
+             r"\s*</span></strong></em></p>"),
+            )
+        for test, expected in cases:
+            needle = re.compile(expected)
+            result = self.parse(test)
+            self.assert_(needle.search(result),
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestInlineCrossing(ParserTestCase):
+    """
+    This test case fail with current parser/formatter and should be fixed in 2.0
+    """
+
+    def disabled_testInlineCrossing(self):
+        """ parser.wiki: prevent inline crossing <a><b></a></b> """
+
+        expected = (r"<p><em>a<strong>ab</strong></em><strong>b</strong>\s*</p>")
+        test = "''a'''ab''b'''\n"
+        needle = re.compile(expected)
+        result = self.parse(test)
+        self.assert_(needle.search(result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestEscapeHTML(ParserTestCase):
+
+    def testEscapeInTT(self):
+        """ parser.wiki: escape html markup in `tt` """
+        test = 'text `<escape-me>` text\n'
+        self._test(test)
+
+    def testEscapeInTT2(self):
+        """ parser.wiki: escape html markup in {{{tt}}} """
+        test = 'text {{{<escape-me>}}} text\n'
+        self._test(test)
+
+    def testEscapeInPre(self):
+        """ parser.wiki: escape html markup in pre """
+        test = '''{{{
+<escape-me>
+}}}
+'''
+        self._test(test)
+
+    def testEscapeInPreHashbang(self):
+        """ parser.wiki: escape html markup in pre with hashbang """
+        test = '''{{{#!
+<escape-me>
+}}}
+'''
+        self._test(test)
+
+    def testEscapeInPythonCodeArea(self):
+        """ parser.wiki: escape html markup in python code area """
+        test = '''{{{#!python
+#<escape-me>
+}}}
+'''
+        self._test(test)
+
+    def testEscapeInGetTextMacro(self):
+        """ parser.wiki: escape html markup in GetText macro """
+        test = "text [[GetText(<escape-me>)]] text"
+        self._test(test)
+
+    def testEscapeInGetTextFormatted(self):
+        """ parser.wiki: escape html markup in getText formatted call """
+        test = self.request.getText('<escape-me>', formatted=1)
+        self._test(test)
+
+    def testEscapeInGetTextFormatedLink(self):
+        """ parser.wiki: escape html markup in getText formatted call with link """
+        test = self.request.getText('["<escape-me>"]', formatted=1)
+        self._test(test)
+
+    def testEscapeInGetTextUnFormatted(self):
+        """ parser.wiki: escape html markup in getText non formatted call """
+        test = self.request.getText('<escape-me>', formatted=0)
+        self._test(test)
+
+    def _test(self, test):
+        expected = r'&lt;escape-me&gt;'
+        result = self.parse(test)
+        self.assert_(re.search(expected, result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestEscapeWikiTableMarkup(ParserTestCase):
+
+    def testEscapeInTT(self):
+        """ parser.wiki: escape wiki table markup in `tt` """
+        test = 'text `||<tablewidth="80"> Table ||` text\n'
+        self.do(test)
+
+    def testEscapeInTT2(self):
+        """ parser.wiki: escape wiki table markup in {{{tt}}} """
+        test = 'text {{{||<tablewidth="80"> Table ||}}} text\n'
+        self.do(test)
+
+    def testEscapeInPre(self):
+        """ parser.wiki: escape wiki table  markup in pre """
+        test = '''{{{
+||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+
+    def testEscapeInPreHashbang(self):
+        """ parser.wiki: escape wiki table  markup in pre with hashbang """
+        test = '''{{{#!
+||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+
+    def testEscapeInPythonCodeArea(self):
+        """ parser.wiki: escape wiki table markup in python code area """
+        test = '''{{{#!python
+# ||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+
+    def do(self, test):
+        expected = r'&lt;tablewidth="80"&gt;'
+        result = self.parse(test)
+        self.assert_(re.search(expected, result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestRule(ParserTestCase):
+    """ Test rules markup """
+
+    def testNotRule(self):
+        """ parser.wiki: --- is no rule """
+        py.test.skip("Broken because of line numbers")
+        result = self.parse('---')
+        expected = '---' # inside <p>
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testStandardRule(self):
+        """ parser.wiki: ---- is standard rule """
+        py.test.skip("Broken because of line numbers")
+        result = self.parse('----')
+        expected = '<hr>'
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testVariableRule(self):
+        """ parser.wiki: ----- rules with size """
+        py.test.skip("Broken because of line numbers")
+
+        for size in range(5, 11):
+            test = '-' * size
+            result = self.parse(test)
+            expected = '<hr class="hr%d">' % (size - 4)
+            self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testLongRule(self):
+        """ parser.wiki: ------------ long rule shortened to hr6 """
+        py.test.skip("Broken because of line numbers")
+        test = '-' * 254
+        result = self.parse(test)
+        expected = '<hr class="hr6">'
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TestBlock(ParserTestCase):
+    cases = (
+        # test, block start
+        ('----\n', '<hr'),
+        ('= Heading =\n', '<h2'),
+        ('{{{\nPre\n}}}\n', '<pre'),
+        ('{{{\n#!python\nPre\n}}}\n', '<div'),
+        ('|| Table ||', '<div'),
+        (' * unordered list\n', '<ul'),
+        (' 1. ordered list\n', '<ol'),
+        (' indented text\n', '<ul'),
+        )
+
+    def testParagraphBeforeBlock(self):
+        """ parser.wiki: paragraph closed before block element """
+        py.test.skip("Broken because of line numbers")
+        text = """AAA
+%s
+"""
+        for test, blockstart in self.cases:
+            # We dont test here formatter white space generation
+            expected = r'<p>AAA\s*</p>\n+%s' % blockstart
+            needle = re.compile(expected, re.MULTILINE)
+            result = self.parse(text % test)
+            match = needle.search(result)
+            self.assert_(match is not None,
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testEmptyLineBeforeBlock(self):
+        """ parser.wiki: empty lines before block element ignored
+        
+        Empty lines separate paragraphs, but should be ignored if a block
+        element follow.
+
+        Currently an empty paragraph is created, which make no sense but
+        no real harm.
+        """
+        py.test.skip("Broken because of line numbers")
+        text = """AAA
+
+%s
+"""
+        for test, blockstart in self.cases:
+            expected = r'<p>AAA\s*</p>\n+%s' % blockstart
+            needle = re.compile(expected, re.MULTILINE)
+            result = self.parse(text % test)
+            match = needle.search(result)
+            self.assert_(match is not None,
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testUrlAfterBlock(self):
+        """ parser.wiki: tests url after block element """
+        cases = ('some text {{{some block text\n}}} and a URL http://moinmo.in/',
+                 'some text {{{some block text\n}}} and a WikiName')
+
+        for case in cases:
+            result = self.parse(case).strip()
+            match = result.endswith('</a>')
+            expected = True
+            self.assert_(match is True,
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testColorizedPythonParserAndNestingPreBrackets(self):
+        """ tests nested {{{ }}} for the python colorized parser 
+        """
+
+        raw = """{{{
+#!python
+import re
+pattern = re.compile(r'{{{This is some nested text}}}')}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        result = "r'{{{This is some nested text}}}'" in output
+        expected = True
+
+        assert expected == result
+
+    def testColorizedPythonParserAndNestingPreBracketsWithLinebreak(self):
+        """ tests nested {{{ }}} for the python colorized parser 
+        """
+
+        raw = """{{{
+#!python
+import re
+pattern = re.compile(r'{{{This is some nested text}}}')
+}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        print output
+        result = "r'{{{This is some nested text}}}'" in output
+        expected = True
+
+        assert expected == result
+
+    def testNestingPreBrackets(self):
+        """ tests nested {{{ }}} for the wiki parser 
+        """
+
+        raw = """{{{
+Example
+You can use {{{brackets}}}}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        result = 'You can use {{{brackets}}}' in output
+        expected = True
+
+        assert expected == result
+
+    def testNestingPreBracketsWithLinebreak(self):
+        """ tests nested {{{ }}} for the wiki parser 
+        """
+
+        raw = """{{{
+Example
+You can use {{{brackets}}}
+}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        print output
+        result = 'You can use {{{brackets}}}' in output
+        expected = True
+
+        assert expected == result
+
+    def testTextBeforeNestingPreBrackets(self):
+        """ tests text before nested {{{ }}} for the wiki parser 
+        """
+
+        raw = """Example
+        {{{
+You can use {{{brackets}}}}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        result = 'Example <span class="anchor" id="line-0"></span><ul><li style="list-style-type:none"><span class="anchor" id="line-0"></span><pre>You can use {{{brackets}}}</pre>' in output
+        expected = True
+
+        assert expected == result
+
+    def testManyNestingPreBrackets(self):
+        """ tests two nestings  ({{{ }}} and {{{ }}}) in one line for the wiki parser 
+        """
+
+        raw = """{{{
+Test {{{brackets}}} and test {{{brackets}}}
+}}}"""
+        output = self.parse(raw)
+        output = ''.join(output)
+        result = '</span><p><pre>Test {{{brackets}}} and test {{{brackets}}}' in output
+        expected = True
+
+        assert expected == result
+
+
--- a/MoinMoin/parser/text_moin_wiki.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/parser/text_moin_wiki.py	Mon Jul 02 13:15:50 2007 +0200
@@ -184,7 +184,6 @@
             result.append(self.formatter.definition_desc(0))
         #result.append("<!-- close item end -->\n")
 
-
     def interwiki(self, target_and_text, **kw):
         # TODO: maybe support [wiki:Page http://wherever/image.png] ?
         scheme, rest = target_and_text.split(':', 1)
@@ -240,7 +239,7 @@
                     pagename = self.formatter.page.page_name
                     url = AttachFile.getAttachUrl(pagename, fname, self.request, escaped=1)
                     return self.formatter.rawHTML(EmbedObject.embed(EmbedObject(macro, wikiutil.escape(fname)), mt, url))
-    
+
         return self.formatter.attachment_link(fname, text)
 
     def _u_repl(self, word):
@@ -280,7 +279,7 @@
 
     def _emph_repl(self, word):
         """Handle emphasis, i.e. '' and '''."""
-        ##print "#", self.is_b, self.is_em, "#"
+        ## print "#", self.is_b, self.is_em, "#"
         if len(word) == 3:
             self.is_b = not self.is_b
             if self.is_em and self.is_b:
@@ -310,7 +309,7 @@
 
     def _emph_ib_or_bi_repl(self, word):
         """Handle mixed emphasis, exactly five '''''."""
-        ##print "*", self.is_b, self.is_em, "*"
+        ## print "*", self.is_b, self.is_em, "*"
         b_before_em = self.is_b > self.is_em > 0
         self.is_b = not self.is_b
         self.is_em = not self.is_em
@@ -319,7 +318,6 @@
         else:
             return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
 
-
     def _sup_repl(self, word):
         """Handle superscript."""
         return self.formatter.sup(1) + \
@@ -344,7 +342,6 @@
             result = result + self.formatter.rule(size)
         return result
 
-
     def _word_repl(self, word, text=None):
         """Handle WikiNames."""
 
@@ -355,7 +352,6 @@
             if not text:
                 text = word
             word = '/'.join([x for x in self.formatter.page.page_name.split('/')[:-1] + [word[wikiutil.PARENT_PREFIX_LEN:]] if x])
-
         if not text:
             # if a simple, self-referencing link, emit it as plain text
             if word == self.formatter.page.page_name:
@@ -407,7 +403,6 @@
                     self.formatter.text(word) +
                     self.formatter.url(0))
 
-
     def _wikiname_bracket_repl(self, text):
         """Handle special-char wikinames with link text, like:
            ["Jim O'Brian" Jim's home page] or ['Hello "world"!' a page with doublequotes]i
@@ -426,7 +421,6 @@
         else:
             return self.formatter.text(text)
 
-
     def _url_bracket_repl(self, word):
         """Handle bracketed URLs."""
         word = word[1:-1] # strip brackets
@@ -470,14 +464,12 @@
                     self.formatter.text(words[1]) +
                     self.formatter.url(0))
 
-
     def _email_repl(self, word):
         """Handle email addresses (without a leading mailto:)."""
         return (self.formatter.url(1, "mailto:" + word, css='mailto') +
                 self.formatter.text(word) +
                 self.formatter.url(0))
 
-
     def _ent_repl(self, word):
         """Handle SGML entities."""
         return self.formatter.text(word)
@@ -544,12 +536,10 @@
         ])
         return ''.join(result)
 
-
     def _indent_level(self):
         """Return current char-wise indent level."""
         return len(self.list_indents) and self.list_indents[-1]
 
-
     def _indent_to(self, new_level, list_type, numtype, numstart):
         """Close and open lists."""
         openlist = []   # don't make one out of these two statements!
@@ -606,7 +596,6 @@
         self.in_list = self.list_types != []
         return ''.join(closelist) + ''.join(openlist)
 
-
     def _undent(self):
         """Close all open lists."""
         result = []
@@ -624,14 +613,12 @@
         self.list_types = []
         return ''.join(result)
 
-
     def _tt_repl(self, word):
         """Handle inline code."""
         return self.formatter.code(1) + \
             self.formatter.text(word[3:-3]) + \
             self.formatter.code(0)
 
-
     def _tt_bt_repl(self, word):
         """Handle backticked inline code."""
         # if len(word) == 2: return "" // removed for FCK editor
@@ -639,7 +626,6 @@
             self.formatter.text(word[1:-1]) + \
             self.formatter.code(0)
 
-
     def _getTableAttrs(self, attrdef):
         # skip "|" and initial "<"
         while attrdef and attrdef[0] == "|":
@@ -775,7 +761,6 @@
         else:
             return self.formatter.text(word)
 
-
     def _heading_repl(self, word):
         """Handle section headings."""
         import sha
@@ -854,14 +839,12 @@
             return self.formatter.text(word)
         return self.formatter.text(word)
 
-
     def _smiley_repl(self, word):
         """Handle smileys."""
         return self.formatter.smiley(word)
 
     _smileyA_repl = _smiley_repl
 
-
     def _comment_repl(self, word):
         # if we are in a paragraph, we must close it so that normal text following
         # in the line below the comment will reopen a new paragraph.
@@ -901,6 +884,8 @@
         ###result.append(u'<span class="info">[scan: <tt>"%s"</tt>]</span>' % line)
         if line.count('{{{') > 1: 
             self.in_nested_pre = line.count('{{{') -  line.count('}}}')
+            if self.in_nested_pre == 0:
+                self.in_nested_pre = 1
             if line.startswith('{{{'):
                 line = line[3:].strip()
             self.in_pre = 'no_parser'
@@ -1010,7 +995,7 @@
         for line in self.lines:
             if ']][[' in line.replace(' ',''):
                 self.no_862 = True
-            self.lineno += 1
+
             self.line_anchor_printed = 0
             if not self.in_table:
                 self.request.write(self._line_anchordef())
@@ -1049,13 +1034,33 @@
                         self.parser_name = parser_name
                         continue
                     else:
-                        self.request.write(self._closeP() +
-                                           self.formatter.preformatted(1))
-                        self.in_pre = 'no_parser'
+                         if not line.count('{{{') > 1:
+                             self.request.write(self._closeP() +
+                                 self.formatter.preformatted(1))
+                         self.in_pre = 'no_parser'
+
                 if self.in_pre == 'found_parser':
+                    self.in_nested_pre += line.count('{{{')
+                    if self.in_nested_pre - line.count('}}}') == 0:
+                        self.in_nested_pre = 1
                     # processing mode
                     try:
-                        endpos = line.index("}}}")
+                        if line.endswith("}}}"):
+                            if self.in_nested_pre == 1:
+                                endpos = len(line) - 3
+                            else:
+                                self.parser_lines.append(line)
+                                self.in_nested_pre -= 1
+                                continue
+                        else:
+                            if self.in_nested_pre == 1:
+                                endpos = line.index("}}}")
+                            else:
+                                self.parser_lines.append(line)
+                                if "}}}" in line:
+                                    self.in_nested_pre -= 1
+                                continue
+
                     except ValueError:
                         self.parser_lines.append(line)
                         continue
@@ -1157,6 +1162,7 @@
             self.request.write(formatted_line)
             if self.in_pre == 'no_parser':
                 self.request.write(self.formatter.linebreak())
+                
 
         # Close code displays, paragraphs, tables and open lists
         self.request.write(self._undent())
@@ -1167,6 +1173,7 @@
         if self.wrapping_div_class:
             self.request.write(self.formatter.div(0))
 
+
     # Private helpers ------------------------------------------------------------
 
     def setParser(self, name):
--- a/MoinMoin/request/__init__.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/request/__init__.py	Mon Jul 02 13:15:50 2007 +0200
@@ -349,7 +349,7 @@
         if self._dicts is None:
             from MoinMoin import wikidicts
             dicts = wikidicts.GroupDict(self)
-            dicts.scandicts()
+            dicts.load_dicts()
             self._dicts = dicts
         return self._dicts
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/request/_tests/test_request.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+"""
+    MoinMoin - MoinMoin.module_tested Tests
+
+    Module names must start with 'test_' to be included in the tests.
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+from MoinMoin import config, wikiutil
+
+class TestNormalizePagename(unittest.TestCase):
+
+    def testPageInvalidChars(self):
+        """ request: normalize pagename: remove invalid unicode chars
+
+        Assume the default setting
+        """
+        test = u'\u0000\u202a\u202b\u202c\u202d\u202e'
+        expected = u''
+        result = self.request.normalizePagename(test)
+        self.assertEqual(result, expected,
+                         ('Expected "%(expected)s" but got "%(result)s"') % locals())
+
+    def testNormalizeSlashes(self):
+        """ request: normalize pagename: normalize slashes """
+        cases = (
+            (u'/////', u''),
+            (u'/a', u'a'),
+            (u'a/', u'a'),
+            (u'a/////b/////c', u'a/b/c'),
+            (u'a b/////c d/////e f', u'a b/c d/e f'),
+            )
+        for test, expected in cases:
+            result = self.request.normalizePagename(test)
+            self.assertEqual(result, expected,
+                             ('Expected "%(expected)s" but got "%(result)s"') %
+                             locals())
+
+    def testNormalizeWhitespace(self):
+        """ request: normalize pagename: normalize whitespace """
+        cases = (
+            (u'         ', u''),
+            (u'    a', u'a'),
+            (u'a    ', u'a'),
+            (u'a     b     c', u'a b c'),
+            (u'a   b  /  c    d  /  e   f', u'a b/c d/e f'),
+            # All 30 unicode spaces
+            (config.chars_spaces, u''),
+            )
+        for test, expected in cases:
+            result = self.request.normalizePagename(test)
+            self.assertEqual(result, expected,
+                             ('Expected "%(expected)s" but got "%(result)s"') %
+                             locals())
+
+    def testUnderscoreTestCase(self):
+        """ request: normalize pagename: underscore convert to spaces and normalized
+
+        Underscores should convert to spaces, then spaces should be
+        normalized, order is important!
+        """
+        cases = (
+            (u'         ', u''),
+            (u'  a', u'a'),
+            (u'a  ', u'a'),
+            (u'a  b  c', u'a b c'),
+            (u'a  b  /  c  d  /  e  f', u'a b/c d/e f'),
+            )
+        for test, expected in cases:
+            result = self.request.normalizePagename(test)
+            self.assertEqual(result, expected,
+                             ('Expected "%(expected)s" but got "%(result)s"') %
+                             locals())
+
+
+class TestGroupPages(unittest.TestCase):
+
+    def setUp(self):
+        self.config = self.TestConfig(page_group_regex=r'.+Group')
+
+    def tearDown(self):
+        del self.config
+
+    def testNormalizeGroupName(self):
+        """ request: normalize pagename: restrict groups to alpha numeric Unicode
+        
+        Spaces should normalize after invalid chars removed!
+        """
+        import re
+        cases = (
+            # current acl chars
+            (u'Name,:Group', u'NameGroup'),
+            # remove than normalize spaces
+            (u'Name ! @ # $ % ^ & * ( ) + Group', u'Name Group'),
+            )
+        for test, expected in cases:
+            # validate we are testing valid group names
+            if wikiutil.isGroupPage(self.request, test):
+                result = self.request.normalizePagename(test)
+                self.assertEqual(result, expected,
+                                 ('Expected "%(expected)s" but got "%(result)s"') %
+                                 locals())
+
+
+class TestHTTPDate(unittest.TestCase):
+
+    def testRFC1123Date(self):
+        """ request: httpDate default rfc1123 """
+        self.failUnlessEqual(self.request.httpDate(0),
+                             'Thu, 01 Jan 1970 00:00:00 GMT',
+                             'wrong date string')
+
+    def testRFC850Date(self):
+        """ request: httpDate rfc850 """
+        self.failUnlessEqual(self.request.httpDate(0, rfc='850'),
+                             'Thursday, 01-Jan-70 00:00:00 GMT',
+                             'wrong date string')
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/search/_tests/test_search.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,36 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.search Tests
+
+    @copyright: 2005 by Nir Soffer <nirs@freeshell.org>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+from MoinMoin import search
+
+
+class TestQuotingBug(unittest.TestCase):
+    """search: quoting bug tests 
+    
+    http://moinmoin.wikiwikiweb.de/MoinMoinBugs/SearchOneCharString
+    
+    This is only a little stupid test for the isQuoted method, because
+    testing parsed queries is much more work.
+    """
+
+    def setUp(self):
+        self.parser = search.QueryParser()
+
+    def testIsQuoted(self):
+        """ search: quoting bug - quoted terms """
+        for case in ('"yes"', "'yes'"):
+            self.assertEqual(self.parser.isQuoted(case), True)
+
+    def testIsNot(self):
+        """ search: quoting bug - unquoted terms """
+        tests = ('', "'", '"', '""', "''", "'\"", '"no', 'no"', "'no",
+                 "no'", '"no\'')
+        for case in tests:
+            self.assertEqual(self.parser.isQuoted(case), False)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/security/_tests/test_security.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,277 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.security Tests
+
+    TODO: when refactoring this, do not use "iter" (is a builtin)
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+                2007 by MoinMoin:ReimarBauer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import py
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+from MoinMoin import security
+
+acliter = security.ACLStringIterator
+
+class TestACLStringIterator(unittest.TestCase):
+
+    def setUp(self):
+        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
+    def tearDown(self):
+        del self.config
+
+    def testEmpty(self):
+        """ security: empty acl string raise StopIteration """
+        iter = acliter(self.request.cfg.acl_rights_valid, '')
+        self.failUnlessRaises(StopIteration, iter.next)
+
+    def testWhiteSpace(self):
+        """ security: white space acl string raise StopIteration """
+        iter = acliter(self.request.cfg.acl_rights_valid, '       ')
+        self.failUnlessRaises(StopIteration, iter.next)
+
+    def testDefault(self):
+        """ security: default meta acl """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'Default Default')
+        for mod, entries, rights in iter:
+            self.assertEqual(entries, ['Default'])
+            self.assertEqual(rights, [])
+
+    def testEmptyRights(self):
+        """ security: empty rights """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['WikiName'])
+        self.assertEqual(rights, [])
+
+    def testSingleWikiNameSingleWrite(self):
+        """ security: single wiki name, single right """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:read')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['WikiName'])
+        self.assertEqual(rights, ['read'])
+
+    def testMultipleWikiNameAndRights(self):
+        """ security: multiple wiki names and rights """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,UserTwo:read,write')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne', 'UserTwo'])
+        self.assertEqual(rights, ['read', 'write'])
+
+    def testMultipleWikiNameAndRightsSpaces(self):
+        """ security: multiple names with spaces """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'user one,user two:read')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user one', 'user two'])
+        self.assertEqual(rights, ['read'])
+
+    def testMultipleEntries(self):
+        """ security: multiple entries """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write UserTwo:read All:')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne'])
+        self.assertEqual(rights, ['read', 'write'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserTwo'])
+        self.assertEqual(rights, ['read'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['All'])
+        self.assertEqual(rights, [])
+
+    def testNameWithSpaces(self):
+        """ security: single name with spaces """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user one'])
+        self.assertEqual(rights, ['read'])
+
+    def testMultipleEntriesWithSpaces(self):
+        """ security: multiple entries with spaces """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read,write user two:read')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user one'])
+        self.assertEqual(rights, ['read', 'write'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user two'])
+        self.assertEqual(rights, ['read'])
+
+    def testMixedNames(self):
+        """ security: mixed wiki names and names with spaces """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write user three,UserFour:read')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne', 'user two'])
+        self.assertEqual(rights, ['read', 'write'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user three', 'UserFour'])
+        self.assertEqual(rights, ['read'])
+
+    def testModifier(self):
+        """ security: acl modifiers """
+        iter = acliter(self.request.cfg.acl_rights_valid, '+UserOne:read -UserTwo:')
+        mod, entries, rights = iter.next()
+        self.assertEqual(mod, '+')
+        self.assertEqual(entries, ['UserOne'])
+        self.assertEqual(rights, ['read'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(mod, '-')
+        self.assertEqual(entries, ['UserTwo'])
+        self.assertEqual(rights, [])
+
+    def testIgnoreInvalidACL(self):
+        """ security: ignore invalid acl
+
+        The last part of this acl can not be parsed. If it ends with :
+        then it will be parsed as one name with spaces.
+        """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read user two is ignored')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne'])
+        self.assertEqual(rights, ['read'])
+        self.failUnlessRaises(StopIteration, iter.next)
+
+    def testEmptyNamesWithRight(self):
+        """ security: empty names with rights
+
+        The documents does not talk about this case, may() should ignore
+        the rights because there is no entry.
+        """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read :read All:')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne'])
+        self.assertEqual(rights, ['read'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, [])
+        self.assertEqual(rights, ['read'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['All'])
+        self.assertEqual(rights, [])
+
+    def testIgnodeInvalidRights(self):
+        """ security: ignore rights not in acl_rights_valid """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,sing,write,drink,sleep')
+        mod, entries, rights = iter.next()
+        self.assertEqual(rights, ['read', 'write'])
+
+    def testBadGuy(self):
+        """ security: bad guy may not allowed anything
+
+        This test was failing on the apply acl rights test.
+        """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write BadGuy: All:read')
+        mod, entries, rights = iter.next()
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['BadGuy'])
+        self.assertEqual(rights, [])
+
+    def testAllowExtraWhitespace(self):
+        """ security: allow extra white space between entries """
+        iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write   user three,UserFour:read  All:')
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['UserOne', 'user two'])
+        self.assertEqual(rights, ['read', 'write'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['user three', 'UserFour'])
+        self.assertEqual(rights, ['read'])
+        mod, entries, rights = iter.next()
+        self.assertEqual(entries, ['All'])
+        self.assertEqual(rights, [])
+
+
+class TestAcl(unittest.TestCase):
+    """ security: testing access control list
+
+    TO DO: test unknown user?
+    """
+    def setUp(self):
+        # Backup user
+        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
+        self.savedUser = self.request.user.name
+
+    def tearDown(self):
+        # Restore user
+        self.request.user.name = self.savedUser
+        del self.config
+
+    def testApplyACLByUser(self):
+        """ security: applying acl by user name"""
+        # This acl string...
+        acl_rights = [
+            "Admin1,Admin2:read,write,delete,revert,admin  "
+            "Admin3:read,write,admin  "
+            "JoeDoe:read,write  "
+            "name with spaces,another one:read,write  "
+            "CamelCase,extended name:read,write  "
+            "BadGuy:  "
+            "All:read  "
+            ]
+        acl = security.AccessControlList(self.request.cfg, acl_rights)
+
+        # Should apply these rights:
+        users = (
+            # user,                 rights
+            # CamelCase names
+            ('Admin1',              ('read', 'write', 'admin', 'revert', 'delete')),
+            ('Admin2',              ('read', 'write', 'admin', 'revert', 'delete')),
+            ('Admin3',              ('read', 'write', 'admin')),
+            ('JoeDoe',              ('read', 'write')),
+            ('SomeGuy',             ('read',)),
+            # Extended names or mix of extended and CamelCase
+            ('name with spaces',    ('read','write',)),
+            ('another one',         ('read','write',)),
+            ('CamelCase',           ('read','write',)),
+            ('extended name',       ('read','write',)),
+            # Blocking bad guys
+            ('BadGuy',              ()),
+            # All other users - every one not mentioned in the acl lines
+            ('All',                 ('read',)),
+            ('Anonymous',           ('read',)),
+            )
+
+        # Check rights
+        for user, may in users:
+            mayNot = [right for right in self.request.cfg.acl_rights_valid
+                      if right not in may]
+            # User should have these rights...
+            for right in may:
+                self.assert_(acl.may(self.request, user, right),
+                    '"%(user)s" should be allowed to "%(right)s"' % locals())
+            # But NOT these:
+            for right in mayNot:
+                self.failIf(acl.may(self.request, user, right),
+                    '"%(user)s" should NOT be allowed to "%(right)s"' % locals())
+
+    def testACLsWithoutEditLogEntry(self):
+        """ tests what are the page rights if edit-log entry doesn't exist
+            for a page where no access is given to
+        """
+        py.test.skip("test tricks out the caching system, page modifications without making an edit-log entry are not supported")
+        import os
+        from MoinMoin.Page import Page
+        pagename = u'AutoCreatedMoinMoinTemporaryTestPage'
+
+        result = self.request.user.may.write(pagename)
+        page = Page(self.request, pagename)
+        path = page.getPagePath(use_underlay=0, check_create=0)
+        if os.path.exists(path):
+            py.test.skip("%s exists. Won't overwrite exiting page" % self.dictPage)
+
+        try:
+            try:
+                os.mkdir(path)
+                revisionsDir = os.path.join(path, 'revisions')
+                os.mkdir(revisionsDir)
+                current = '00000001'
+                file(os.path.join(path, 'current'), 'w').write('%s\n' % current)
+                text = u'#acl All: \n'
+                file(os.path.join(revisionsDir, current), 'w').write(text)
+            except Exception, err:
+                py.test.skip("Can not be create test page: %s" % err)
+    
+            assert not self.request.user.may.write(pagename)
+        finally:
+            if os.path.exists(path):
+                import shutil
+                shutil.rmtree(path, True)
+
--- a/MoinMoin/server/STANDALONE.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/server/STANDALONE.py	Mon Jul 02 13:15:50 2007 +0200
@@ -485,8 +485,17 @@
 
 def quit(signo, stackframe):
     """ Signal handler for aborting signals """
-    global httpd
+    global httpd, config
     logging.info("Thanks for using MoinMoin!")
+
+    fname = config.pycallgraph_output
+    if fname:
+         import pycallgraph
+         if fname.endswith('.png'):
+             pycallgraph.make_dot_graph(fname)
+         elif fname.endswith('.dot'):
+             pycallgraph.save_dot(fname)
+         
     if httpd:
         httpd.die()
 
@@ -550,7 +559,7 @@
     # Development options
     memoryProfile = None
     hotshotProfile = None
-
+    pycallgraph_output = None
 
 def run(configClass):
     """ Create and run a moin server
@@ -580,6 +589,20 @@
         MoinRequestHandler.serve_moin = memoryProfileDecorator(
             MoinRequestHandler.serve_moin, config.memoryProfile)
 
+    # initialize pycallgraph, if wanted
+    if config.pycallgraph_output:
+        try:
+            import pycallgraph
+            pycallgraph.settings['include_stdlib'] = False
+            pcg_filter = pycallgraph.GlobbingFilter(exclude=['pycallgraph.*',
+                                                             'unknown.*',
+                                                    ],
+                                                    max_depth=9999)
+            pycallgraph.start_trace(reset=True, filter_func=pcg_filter)
+        except ImportError:
+            config.pycallgraph_output = None
+
+
     registerSignalHandlers(quit)
     httpd = makeServer(config)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/widget/_tests/test_html.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,66 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.widget.html Tests
+
+    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+from MoinMoin.widget import html
+
+class TestHTMLWidgets(unittest.TestCase):
+    """widget.html: testing html widgets"""
+
+    def testCreate(self):
+        """widget.html: creating html widgets
+
+        TO DO: add tests for all elements by HTML 4 spec.
+        """
+        tests = (
+            # description, call, expected           
+            ('Create text', html.Text('<br> &'), '&lt;br&gt; &amp;'),
+            ('Create raw html', html.Raw('<br> &amp;'), '<br> &amp;'),
+            ('Create br', html.BR(), '<br>'),
+            ('Create hr', html.HR(), '<hr>'),
+            ('Create p', html.P(), '<p></p>'),
+            )
+
+        for description, obj, expected in tests:
+            result = unicode(obj)
+            self.assertEqual(result, expected,
+                             ('%(description)s: expected "%(expected)s" '
+                              'but got "%(result)s"') % locals())
+
+    def testInvalidAttributes(self):
+        """widegt.html: invalid attributes raises exception
+
+        TO DO: add tests for all elements by HTML 4 spec.
+        """
+        self.assertRaises(AttributeError, html.BR, name='foo')
+
+
+    def testCompositeElements(self):
+        """widget.html: append to and extend composite element"""
+        html._SORT_ATTRS = 1
+        element = html.P()
+
+        actions = (
+            # action, data, expected
+            (element.append,
+             html.Text('Text & '),
+             '<p>Text &amp; </p>'),
+            (element.append,
+             html.Text('more text. '),
+             '<p>Text &amp; more text. </p>'),
+            (element.extend,
+             (html.Text('And then '), html.Text('some.')),
+             '<p>Text &amp; more text. And then some.</p>'),
+            )
+
+        for action, data, expected in actions:
+            action(data)
+            result = unicode(element)
+            self.assertEqual(result, expected,
+                             'Expected "%(expected)s" but got "%(result)s"' % locals())
+
--- a/MoinMoin/wikidicts.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/wikidicts.py	Mon Jul 02 13:15:50 2007 +0200
@@ -2,76 +2,54 @@
 """
     MoinMoin - Dictionary / Group Functions
 
-    @copyright: 2003-2006 MoinMoin:ThomasWaldmann,
-                2003 by Gustavo Niemeyer, http://moin.conectiva.com.br/GustavoNiemeyer
+    @copyright: 2003-2007 MoinMoin:ThomasWaldmann,
+                2003 by Gustavo Niemeyer
     @license: GNU GPL, see COPYING for details.
 """
 import re, time
 
-#import copy #broken, see comments at top of this file:
 from MoinMoin.support import copy
 
 from MoinMoin import caching, wikiutil, Page, logfile
 from MoinMoin.logfile.editlog import EditLog
 
-# Version of the internal data structure which is pickled
-# Please increment if you have changed the structure
-DICTS_PICKLE_VERSION = 5
+# Version of the internal data structure which is pickled.
+# Please increment if you have changed the structure.
+DICTS_PICKLE_VERSION = 6
 
 
-class DictBase:
+class DictBase(dict):
     """ Base class for wiki dicts
 
-    To use this class, sub class it and override regex and initFromText.
+    To use this class, subclass it and override regex and initFromText.
     """
-    # Regular expression used to parse text - sub class should override this
-    regex = ''
-
-    def __init__(self, request, name):
-        """ Initialize, starting from <nothing>.
+    def __init__(self, request=None, pagename=None):
+        dict.__init__(self)
+        self.name = None
+        if request is not None and pagename is not None:
+            self.loadFromPage(request, pagename)
 
-        Create a dict from a wiki page.
-        """
-        self.name = name
-
-        self.initRegex()
-
-        # Get text from page named 'name'
-        p = Page.Page(request, name)
-        text = p.get_raw_body()
-        self.initFromText(text)
-
+    # Regular expression used to parse text - subclass should override this
+    regex = ''
     def initRegex(cls):
         """ Make it a class attribute to avoid it being pickled. """
         cls.regex = re.compile(cls.regex, re.MULTILINE | re.UNICODE)
     initRegex = classmethod(initRegex)
 
-    def initFromText(self, text):
-        raise NotImplementedError('sub classes should override this')
-
-    def keys(self):
-        return self._dict.keys()
+    def loadFromPage(self, request, name):
+        """ load the dict from wiki page <name>'s content """
+        self.name = name
+        self.initRegex()
+        text = Page.Page(request, name).get_raw_body()
+        self.initFromText(text)
 
-    def values(self):
-        return self._dict.values()
-    
-    def get_dict(self):
-        return self._dict
+    def initFromText(self, text):
+        """ parse the wiki page text and init the dict from it """
+        raise NotImplementedError('subclasses should override this')
 
-    def has_key(self, key):
-        return self._dict.has_key(key)
-
-    def get(self, key, default):
-        return self._dict.get(key, default)
-
-    def __getitem__(self, key):
-        return self._dict[key]
-
-    def __repr__(self):
-        return "<DictBase name=%r items=%r>" % (self.name, self._dict.items())
 
 class Dict(DictBase):
-    """ Mapping of keys to values in a wiki page
+    """ Mapping of keys to values in a wiki page.
 
        How a Dict definition page should look like:
 
@@ -87,20 +65,16 @@
     regex = r'^ (?P<key>.+?):: (?P<val>.*?) *$'
 
     def initFromText(self, text):
-        """ Create dict from keys and values in text
-
-        Invoked by __init__, also useful for testing without a page.
-        """
-        self._dict = {}
         for match in self.regex.finditer(text):
             key, val = match.groups()
-            self._dict[key] = val
+            self[key] = val
 
     def __repr__(self):
-        return "<Dict name=%r items=%r>" % (self.name, self._dict.items())
+        return "<Dict name=%r items=%r>" % (self.name, self.items())
+
 
 class Group(DictBase):
-    """ Group of users, of pages, of whatever
+    """ Group of users, of pages, of whatever.
 
     How a Group definition page should look like:
 
@@ -112,81 +86,41 @@
      * memberN
     any text ignored
 
-    if there are any free links using ["free link"] notation, the markup
-    is stripped from the member 
+    If there are any free links using ["free link"] notation, the markup
+    is stripped from the member.
     """
-    # * Member - ignore all but first level list items, strip whitespace
-    # Strip free links markup if exists
+    # * Member - ignore all but first level list items, strip whitespace,
+    # strip free links markup if exists.
     regex = r'^ \* +(?:\[\")?(?P<member>.+?)(?:\"\])? *$'
 
     def initFromText(self, text):
-        """ Create dict from group members in text
-
-        Invoked by __init__, also useful for testing without a page.
-        """
-        self._dict = {}
         for match in self.regex.finditer(text):
-            self._dict[match.group('member')] = 1
+            member = match.group('member')
+            self.addmember(member)
 
     def members(self):
-        return self._dict.keys()
+        """ return the group's members """
+        return self.keys()
 
     def addmembers(self, members):
+        """ add a list of members to the group """
         for m in members:
             self.addmember(m)
 
     def addmember(self, member):
-        self._dict[member] = 1
+        """ add a member to the group """
+        self[member] = 1
 
     def has_member(self, member):
-        return self._dict.has_key(member)
-
-    def _expandgroup(self, groupdict, name):
-        """ Recursively expand group
-
-        If a group contain another group, the members of that group are
-        added into the the group. The group name itself is not replaced.
-
-        Given two groups:
-
-            MainGruop = [A, SubGroup]
-            SubGroup = [B, C]
-
-        MainGroup is expanded to:
-
-            MainGroup = [A, SubGroup, B, C]
-            
-        This behavior is important for things like SystemPagesGroup,
-        when we like to know if a page is a system page group. page may
-        be a page or a page group, like SystemPagesGroupInFrenchGroup.
-
-        This behavior has no meaning for users groups used in ACL,
-        because user can not use a group name. Note that if you allow a
-        user to use a group name, one can gain a sub group privileges by
-        registering a user with that group name.
-        """
-        groupmembers = groupdict.members(name)
-        members = {}
-        for member in groupmembers:
-            # Skip self duplicates
-            if member == self.name:
-                continue
-            # Add member and its children
-            members[member] = 1
-            if groupdict.hasgroup(member):
-                members.update(self._expandgroup(groupdict, member))
-        return members
-
-    def expandgroups(self, groupdict):
-        """ Invoke _expandgroup to recursively expand groups """
-        self._dict = self._expandgroup(groupdict, self.name)
+        """ check if the group has member <member> """
+        return self.has_key(member)
 
     def __repr__(self):
-        return "<Group name=%r items=%r>" % (self.name, self._dict.keys())
+        return "<Group name=%r items=%r>" % (self.name, self.keys())
 
 
 class DictDict:
-    """a dictionary of Dict objects
+    """ a dictionary of Dict objects
 
        Config:
            cfg.page_dict_regex
@@ -204,51 +138,53 @@
         self.picklever = DICTS_PICKLE_VERSION
 
     def has_key(self, dictname, key):
-        dict = self.dictdict.get(dictname)
-        return dict and dict.has_key(key)
+        """ check if we have key <key> in dict <dictname> """
+        d = self.dictdict.get(dictname)
+        return d and d.has_key(key)
 
     def keys(self, dictname):
-        """get keys of dict <dictname>"""
+        """ get keys of dict <dictname> """
         try:
-            dict = self.dictdict[dictname]
+            d = self.dictdict[dictname]
         except KeyError:
             return []
-        return dict.keys()
+        return d.keys()
 
     def values(self, dictname):
-        """get values of dict <dictname>"""
+        """ get values of dict <dictname> """
         try:
-            dict = self.dictdict[dictname]
+            d = self.dictdict[dictname]
         except KeyError:
             return []
-        return dict.values()
+        return d.values()
 
     def dict(self, dictname):
-        """get dict <dictname>"""
+        """ get dict <dictname> """
         try:
-            dict = self.dictdict[dictname]
+            d = self.dictdict[dictname]
         except KeyError:
             return {}
-        return dict
+        return d
 
     def adddict(self, request, dictname):
-        """add a new dict (will be read from the wiki page)"""
+        """ add a new dict (will be read from the wiki page) """
         self.dictdict[dictname] = Dict(request, dictname)
 
     def has_dict(self, dictname):
+        """ check if we have a dict <dictname> """
         return self.dictdict.has_key(dictname)
 
     def keydict(self, key):
-        """list all dicts that contain key"""
+        """ list all dicts that contain key """
         dictlist = []
-        for dict in self.dictdict.values():
-            if dict.has_key(key):
-                dictlist.append(dict.name)
+        for d in self.dictdict.values():
+            if d.has_key(key):
+                dictlist.append(d.name)
         return dictlist
 
 
 class GroupDict(DictDict):
-    """a dictionary of Group objects
+    """ a dictionary of Group objects
 
        Config:
            cfg.page_group_regex
@@ -262,17 +198,16 @@
     def reset(self):
         self.dictdict = {}
         self.groupdict = {} # unexpanded groups
-        self.namespace_timestamp = 0
-        self.pageupdate_timestamp = 0
-        self.base_timestamp = 0
         self.picklever = DICTS_PICKLE_VERSION
+        self.disk_cache_mtime = 0
 
     def has_member(self, groupname, member):
+        """ check if we have <member> as a member of group <groupname> """
         group = self.dictdict.get(groupname)
         return group and group.has_member(member)
 
     def members(self, groupname):
-        """get members of group <groupname>"""
+        """ get members of group <groupname> """
         try:
             group = self.dictdict[groupname]
         except KeyError:
@@ -280,130 +215,142 @@
         return group.members()
 
     def addgroup(self, request, groupname):
-        """add a new group (will be read from the wiki page)"""
+        """ add a new group (will be read from the wiki page) """
         grp = Group(request, groupname)
-        self.dictdict[groupname] = grp
         self.groupdict[groupname] = grp
+        self.expand_groups()
 
     def hasgroup(self, groupname):
+        """ check if we have a dict <dictname> """
         return self.groupdict.has_key(groupname)
 
+    def __getitem__(self, name):
+        return self.groupdict[name]
+
     def membergroups(self, member):
-        """list all groups where member is a member of"""
+        """ list all groups where member is a member of """
         grouplist = []
         for group in self.dictdict.values():
             if group.has_member(member):
                 grouplist.append(group.name)
         return grouplist
 
-    def scandicts(self):
-        """scan all pages matching the dict / group regex and init the dictdict"""
-        dump = 0
-        request = self.request
+    def expand_groups(self):
+        """ copy expanded groups to self.dictdict """
+        for name in self.groupdict:
+            members, groups = self.expand_group(name)
+            members.update(groups)
+            grp = Group()
+            grp.update(members)
+            self.dictdict[name] = grp
 
-        # Save now in our internal version format
-        now = wikiutil.timestamp2version(int(time.time()))
-        try:
-            lastchange = EditLog(request).date()
-        except logfile.LogMissing:
-            lastchange = 0
-            dump = 1
+    def expand_group(self, name):
+        """ Recursively expand group <name>, using the groupdict (which is a not expanded
+            dict of all group names -> group dicts). We return a flat list of group member
+            names and group names.
 
+        Given a groupdict (self) with two groups:
+
+            MainGroup: [A, SubGroup]
+            SubGroup: [B, C]
+
+        MainGroup is expanded to:
+
+            self.expand_group('MainGroup') -> [A, B, C], [MainGroup, SubGroup]
+        """
+        groups = {name: 1}
+        members = {}
+        groupmembers = self[name].keys()
+        for member in groupmembers:
+            # Skip duplicates
+            if member in groups:
+                continue
+            # Add member and its children
+            if self.hasgroup(member):
+                new_members, new_groups = self.expand_group(member)
+                groups.update(new_groups)
+                members.update(new_members)
+            else:
+                members[member] = 1
+        return members, groups
+
+    def load_dicts(self):
+        """ load the dict from the cache """
+        request = self.request
+        rescan = False
         arena = 'wikidicts'
         key = 'dicts_groups'
+        cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
+        current_disk_cache_mtime = cache.mtime()
         try:
             self.__dict__.update(self.cfg.cache.DICTS_DATA)
+            if current_disk_cache_mtime > self.disk_cache_mtime:
+                self.reset()
+                raise AttributeError # not fresh, force load from disk
+            else:
+                return
         except AttributeError:
             try:
-                cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
                 data = cache.content()
                 self.__dict__.update(data)
+                self.disk_cache_mtime = current_disk_cache_mtime
 
                 # invalidate the cache if the pickle version changed
                 if self.picklever != DICTS_PICKLE_VERSION:
-                    self.reset()
-                    dump = 1
+                    raise # force rescan
             except:
                 self.reset()
-                dump = 1
-
-        if lastchange >= self.namespace_timestamp or dump:
-            isdict = self.cfg.cache.page_dict_regex.search
-            isgroup = self.cfg.cache.page_group_regex.search
-
-            # check for new groups / dicts from time to time...
-            if now - self.namespace_timestamp >= wikiutil.timestamp2version(60): # 60s
-                # Get all pages in the wiki - without user filtering using filter
-                #function - this make the page list about 10 times faster.
-                dictpages = request.rootpage.getPageList(user='', filter=isdict)
-                grouppages = request.rootpage.getPageList(user='', filter=isgroup)
-
-                # remove old entries when dict or group page have been deleted,
-                # add entries when pages have been added
-                # use copies because the dicts are shared via cfg.cache.DICTS_DATA
-                #  and must not be modified
-                olddictdict = self.dictdict.copy()
-                oldgroupdict = self.groupdict.copy()
-                self.dictdict = {}
-                self.groupdict = {}
+                rescan = True
 
-                for pagename in dictpages:
-                    if olddictdict.has_key(pagename):
-                        # keep old
-                        self.dictdict[pagename] = olddictdict[pagename]
-                        del olddictdict[pagename]
-                    else:
-                        self.adddict(request, pagename)
-                        dump = 1
-
-                for pagename in grouppages:
-                    if olddictdict.has_key(pagename):
-                        # keep old
-                        self.dictdict[pagename] = olddictdict[pagename]
-                        self.groupdict[pagename] = oldgroupdict[pagename]
-                        del olddictdict[pagename]
-                    else:
-                        self.addgroup(request, pagename)
-                        dump = 1
-
-                if olddictdict: # dict page was deleted
-                    dump = 1
-
-                self.namespace_timestamp = now
-
-            # check if groups / dicts have been modified on disk
-            for pagename in self.dictdict.keys():
-                if Page.Page(request, pagename).mtime_usecs() >= self.pageupdate_timestamp:
-                    if isdict(pagename):
-                        self.adddict(request, pagename)
-                    elif isgroup(pagename):
-                        self.addgroup(request, pagename)
-                    dump = 1
-            self.pageupdate_timestamp = now
-
-            if not self.base_timestamp:
-                self.base_timestamp = int(time.time())
+        if rescan:
+            self.scan_dicts()
+            self.load_dicts() # try again
+            return
 
         data = {
-            "namespace_timestamp": self.namespace_timestamp,
-            "pageupdate_timestamp": self.pageupdate_timestamp,
-            "base_timestamp": self.base_timestamp,
+            "disk_cache_mtime": self.disk_cache_mtime,
             "dictdict": self.dictdict,
             "groupdict": self.groupdict,
             "picklever": self.picklever
         }
 
-        if dump:
-            # copy unexpanded groups to self.dictdict
-            for name, grp in self.groupdict.items():
-                self.dictdict[name] = copy.deepcopy(grp)
-            # expand groups
-            for name in self.groupdict:
-                self.dictdict[name].expandgroups(self)
-
-            cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
-            cache.update(data)
-
         # remember it (persistent environments)
         self.cfg.cache.DICTS_DATA = data
 
+    def scan_dicts(self):
+        """ scan all pages matching the dict / group regex and
+            cache the results on disk
+        """
+        request = self.request
+        self.reset()
+
+        # XXX get cache write lock here
+        scan_begin_time = time.time()
+
+        # Get all pages in the wiki - without user filtering using filter
+        # function - this makes the page list about 10 times faster.
+        isdict = self.cfg.cache.page_dict_regex.search
+        dictpages = request.rootpage.getPageList(user='', filter=isdict)
+        for pagename in dictpages:
+            self.adddict(request, pagename)
+
+        isgroup = self.cfg.cache.page_group_regex.search
+        grouppages = request.rootpage.getPageList(user='', filter=isgroup)
+        for pagename in grouppages:
+            self.addgroup(request, pagename)
+
+        scan_end_time = time.time()
+        self.expand_groups()
+
+        arena = 'wikidicts'
+        key = 'dicts_groups'
+        cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
+        data = {
+            "scan_begin_time": scan_begin_time,
+            "scan_end_time": scan_end_time,
+            "dictdict": self.dictdict,
+            "groupdict": self.groupdict,
+            "picklever": self.picklever
+        }
+        cache.update(data)
+        # XXX release cache write lock here
--- a/MoinMoin/wikiutil.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/MoinMoin/wikiutil.py	Mon Jul 02 13:15:50 2007 +0200
@@ -494,6 +494,8 @@
 
 def unquoteName(name):
     """ if there are quotes around the name, strip them """
+    if not name:
+        return name
     for quote_char in QUOTE_CHARS:
         if quote_char == name[0] == name[-1]:
             return name[1:-1]
@@ -1605,7 +1607,22 @@
 def createTicket(request, tm=None):
     """Create a ticket using a site-specific secret (the config)"""
     import sha
-    ticket = tm or "%010x" % time.time()
+    if tm is None:
+        tm = "%010x" % time.time()
+
+    # make the ticket specific to the page and action:
+    try:
+        pagename = quoteWikinameURL(request.page.page_name)
+    except:
+        pagename = 'None'
+
+    try:
+        action = request.action
+    except:
+        action = 'None'
+
+
+    ticket = "%s.%s.%s" % (tm, pagename, action)
     digest = sha.new()
     digest.update(ticket)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/wikixml/_tests/test_marshal.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,56 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.wikixml.marshal Tests
+
+    @copyright: 2002-2004 by Juergen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest # LEGACY UNITTEST, PLEASE DO NOT IMPORT unittest IN NEW TESTS, PLEASE CONSULT THE py.test DOCS
+import array
+from MoinMoin.wikixml import marshal
+
+class TestMarshal(unittest.TestCase):
+    """Testing Marshal used for ...XXX"""
+
+    class Data:
+        cvar = 'Class Variable'
+        def __init__(self, value):
+            self.ivar = value
+
+    prop = (
+        # value, xml representation in a marshal object
+        (None, '<data><prop><none/></prop></data>'),
+        ("string", '<data><prop>string</prop></data>'),
+        ([1, "abc"], '<data><prop><item>1</item><item>abc</item></prop></data>'),
+        ((1, "abc"), '<data><prop><item>1</item><item>abc</item></prop></data>'),
+        ({"abc": 1}, '<data><prop><abc>1</abc></prop></data>'),
+        (1, '<data><prop>1</prop></data>'),
+        (Data('value'), '<data><prop><data><ivar>value</ivar></data></prop></data>'),
+        (array.array("i", [42]), "<data><prop>array('i', [42])</prop></data>"),
+        (buffer("0123456789", 2, 3), "<data><prop>234</prop></data>"),
+        )
+
+    def setUp(self):
+        self.obj = marshal.Marshal()
+
+    def testCreateMarshal(self):
+        """wikixml.marshal: create new marshal"""
+        self._checkData(self.obj, '<data></data>')
+
+    def testSetMarshalProperty(self):
+        """wikixml.marshal: setting marshal property"""
+        for value, xml in self.prop:
+            self.obj.prop = value
+            self._checkData(self.obj, xml)
+
+    def _canonize(self, xml):
+        xml = xml.replace('\n', '')
+        return xml
+
+    def _checkData(self, obj, xml):
+        objXML = self._canonize(obj.toXML())
+        expected = self._canonize(xml)
+        self.assertEqual(objXML, expected,
+            'Expected "%(expected)s" but got "%(objXML)s"' % locals())
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/xmlrpc/_tests/test_multicall.py	Mon Jul 02 13:15:50 2007 +0200
@@ -0,0 +1,26 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.xmlrpc.xmlrpc_system_multicall Fault serialization
+
+    @copyright: 2007 by Karol Nowak <grywacz@gmail.com>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from MoinMoin.xmlrpc import XmlRpcBase
+from xmlrpclib import Fault
+
+def xmlrpc_return_fault():
+    return Fault(666, "Fault description")
+
+def test_fault_serialization(request):
+    xmlrpc = XmlRpcBase(request)
+    xmlrpc.xmlrpc_return_fault = xmlrpc_return_fault
+    args = [{'methodName': 'return_fault', 'params': [ ]}]
+    
+    print """If a XML RPC method returns a Fault, we should get a failure response
+    instead of a serialized Fault, as it happened in the past. See revision
+    8b7d6d70fc95 for details"""
+    
+    result = xmlrpc.xmlrpc_system_multicall(args)
+    assert type(result[0]) == dict
+    assert result[0].has_key("faultCode") and result[0].has_key("faultString")
--- a/moin.py	Sun Jun 24 01:20:44 2007 +0200
+++ b/moin.py	Mon Jul 02 13:15:50 2007 +0200
@@ -127,6 +127,11 @@
     # Not compatible with threads - use with SimpleServer only.
     ## hotshotProfile = name + '.prof'
 
+    # Using pycallgraph to make nice graphics of how moin works internally
+    # hint: using zgrviewer to view .dot is much more effective than using
+    #       some .png viewer
+    ##pycallgraph_output = 'moin-pycallgraph.dot' # can be either .dot or .png
+    ##serverClass = 'SimpleServer' # pycallgraph doesn't support multithreading
 
 try:
     from wikiserverconfig import Config
--- a/tests/rpctest.py	Sun Jun 24 01:20:44 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-import xmlrpclib
-
-if __name__ == "__main__":
-
-    server = xmlrpclib.ServerProxy('http://127.0.0.1/cgi-bin/wiki.bat/?action=xmlrpc')
-    print server
-
-    try:
-        frontpage = server.getPage('FrontPage').data.decode('UTF-8')
-        print "Length of FrontPage:", len(frontpage)
-        print "Start of FrontPage:", repr(frontpage[:50]), "..."
-        print "End of FrontPage:", "...", repr(frontpage[-50:])
-        print "Interface Version:", server.getRPCVersionSupported()
-        print "Number of Pages:", len(server.getAllPages())
-    except xmlrpclib.Error, v:
-        print "ERROR", v
-