changeset 2006:1339d6fdc4ff

Changed tests to use py.test. Also changed the semantics a bit - the test wiki directory is only created freshly if it does not exist.
author Alexander Schremmer <alex AT alexanderweb DOT de>
date Fri, 20 Apr 2007 00:12:50 +0200
parents 511924c36086
children 6cc2e0544657 c4cbabe9a02d
files Makefile MoinMoin/_tests/__init__.py MoinMoin/_tests/_test_template.py MoinMoin/_tests/broken/test_converter_text_html_text_moin_wiki.py MoinMoin/_tests/broken/test_parser_text_moin_wiki.py MoinMoin/_tests/compat.py MoinMoin/_tests/maketestwiki.py MoinMoin/_tests/test_Page.py MoinMoin/_tests/test_PageEditor.py MoinMoin/_tests/test_converter_text_html_text_moin_wiki.py MoinMoin/_tests/test_error.py MoinMoin/_tests/test_formatter.py MoinMoin/_tests/test_i18n.py MoinMoin/_tests/test_macro.py MoinMoin/_tests/test_mail_sendmail.py MoinMoin/_tests/test_packages.py MoinMoin/_tests/test_parser_text_moin_wiki.py MoinMoin/_tests/test_pysupport.py MoinMoin/_tests/test_request.py MoinMoin/_tests/test_search.py MoinMoin/_tests/test_security.py MoinMoin/_tests/test_user.py MoinMoin/_tests/test_util_lock.py MoinMoin/_tests/test_util_web.py MoinMoin/_tests/test_widget_html.py MoinMoin/_tests/test_wikidicts.py MoinMoin/_tests/test_wikisync.py MoinMoin/_tests/test_wikiutil.py MoinMoin/_tests/test_wikixml_marshal.py MoinMoin/action/test.py MoinMoin/conftest.py tests/make_test.out tests/maketestwiki.py tests/runtests.py tests/wikiconfig.py
diffstat 35 files changed, 2031 insertions(+), 2205 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Thu Apr 19 12:55:07 2007 +0200
+++ b/Makefile	Fri Apr 20 00:12:50 2007 +0200
@@ -50,7 +50,7 @@
 	cd $(share); rm -rf underlay.tar.bz2; tar cjf underlay.tar.bz2 underlay
 
 pagepacks:
-	@python tests/maketestwiki.py
+	@python MoinMoin/_tests/maketestwiki.py
 	@MoinMoin/script/moin.py --config-dir=$(testwiki)/.. maint mkpagepacks
 	cd $(share) ; rm -rf underlay
 	cp -a $(testwiki)/underlay $(share)/
@@ -77,12 +77,12 @@
 update-underlay:
 	cd $(share); rm -rf underlay; tar xjf underlay.tar.bz2
 
-test: 
-	@python tests/maketestwiki.py
-	@python tests/runtests.py
+test:
+	@echo Testing is now done using \`py.test\`. py.test can be installed by downloading from http://codespeak.net/py/dist/download.html
+	@echo Writing tests is explained on http://codespeak.net/py/dist/test.html
 
 coverage:
-	@python tests/maketestwiki.py
+	@python MoinMoin/_tests/maketestwiki.py
 	@python -u -m trace --count --coverdir=cover --missing tests/runtests.py
 
 pylint:
--- a/MoinMoin/_tests/__init__.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/__init__.py	Fri Apr 20 00:12:50 2007 +0200
@@ -1,191 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-MoinMoin Testing Framework
---------------------------
-
-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_pakcage_module.
-
-Each test_ module may contain test case classes sub classed from
-unittest.TestCase or subclass of it. Previous versions required TestCase
-suffix, but now its only a convention.
-
-Each test case class may contain multiply test methods, that must start
-with 'test'. Those methods will be run by the test suites.
-
-Test 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.
-
-See _test_template.py for an example, and use it to create new tests.
-
-Typical Usage
--------------
-
-Running all test in this package::
-
-    from MoinMoin._tests import run
-    run(request)
-
-Running only few modules::
-
-    run(request, names=['test_this', 'test_that'])
-
-@copyright: 2002-2004 by Juergen Hermann <jh@web.de>
-@license: GNU GPL, see COPYING for details.
-"""
-
-import sys
-
-from unittest import TestLoader, TextTestRunner
-
-
-class TestSkipped(Exception):
-    """ Raised when a tests is skipped """
-
-TestSkiped = TestSkipped # ensure a stable interface
-
-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 
-    the default datetime_fmt.
-    
-    When you set custom values in a TestConfig, the previous values are saved,
-    and when the TestConfig is deleted, they are restored automatically.
-    
-    Typical Usage
-    -------------
-    ::
-        from MoinMoin._tests import TestConfig
-        class SomeTestCase(unittest.TestCase):
-            def setUp(self):
-                self.config = TestConfig(self.request,
-                                         defaults=key_list, key=value,...)
-            def tearDown(self):
-                del self.config
-            def testSomething(self):
-                # test that needs those defaults and custom values
-    """
-
-    def __init__(self, request, defaults=(), **custom):
-        """ Create temporary configuration for a test 
-
-        @param request: current request
-        @param defaults: list of keys that should use the default value
-        @param custom: other keys using non default values, or new keys
-               that request.cfg does not have already
-        """
-        self.request = request
-        self.old = {}  # Old config values
-        self.new = []  # New added attributes
-        self.setDefaults(defaults)
-        self.setCustom(**custom)
-
-    def setDefaults(self, defaults=()):
-        """ Set default values for keys in defaults list
-        
-        Non existing default will raise an AttributeError.
-        """
-        from MoinMoin.config import multiconfig
-        for key in defaults:
-            self._setattr(key, getattr(multiconfig.DefaultConfig, key))
-
-    def setCustom(self, **custom):
-        """ Set custom values """
-        for key, value in custom.items():
-            self._setattr(key, value)
-
-    def _setattr(self, key, value):
-        """ Set a new value for key saving new added keys """
-        if hasattr(self.request.cfg, key):
-            self.old[key] = getattr(self.request.cfg, key)
-        else:
-            self.new.append(key)
-        setattr(self.request.cfg, key, value)
-
-    def __del__(self):
-        """ Restore previous request.cfg 
-        
-        Set old keys to old values and delete new keys.
-        """
-        for key, value in self.old.items():
-            setattr(self.request.cfg, key, value)
-        for key in self.new:
-            delattr(self.request.cfg, key)
-
-
-class MoinTestLoader(TestLoader):
-    """ Customized test loader that support long running process
-
-    To enable testing long running process, we inject the current
-    request into each test case class. Later, each test can refer to
-    request as self.request.
-    """
-    def __init__(self, request):
-        self.request = request
-
-    def loadTestsFromTestCase(self, testCaseClass):
-        testCaseClass.request = self.request
-        return TestLoader.loadTestsFromTestCase(self, testCaseClass)
-
-    def loadTestsFromModuleNames(self, names):
-        """ Load tests from qualified module names, eg. a.b.c
-        
-        loadTestsFromNames is broken, hiding ImportErrros in test
-        modules. This method is less flexsible but works correctly.
-        """
-        names = ['%s.%s' % (__name__, name) for name in names]
-        suites = []
-        for name in names:
-            module = __import__(name, globals(), {}, ['dummy'])
-            suites.append(self.loadTestsFromModule(module))
-        return self.suiteClass(suites)
-
-
-def makeSuite(request, names=None):
-    """ Create test suites from modules in names
-
-    @param request: current request
-    @param names: module names to get tests from. If the list is empty,
-        all test modules in the _tests package are used.
-    @rtype: C{unittest.TestSuite}
-    @return: test suite with all test cases in names
-    """
-    if not names:
-        from MoinMoin.util.pysupport import getPackageModules
-        names = getPackageModules(__file__)
-        names = [name for name in names if name.startswith('test_')]
-        caseInsensitiveCompare = lambda a, b: cmp(a.lower(), b.lower())
-        names.sort(caseInsensitiveCompare)
-
-    return MoinTestLoader(request).loadTestsFromModuleNames(names)
-
-
-def run(request=None, names=None):
-    """ Run test suit
-
-    @param request: current request
-    @param names: list fully qualified module names to test,
-        e.g MoinMoin._tests.test_error
-    """
-    if request is None:
-        from MoinMoin.request import CLI
-        from MoinMoin.user import User
-        request = CLI.Request()
-        request.form = request.args = request.setup_args()
-        request.user = User(request)
-
-    suite = makeSuite(request, names)
-
-    # do not redirect the stream to request here because request.write can
-    # be invalid or broken because not all redirections of it use a finally: block
-    TextTestRunner(stream=sys.stdout, verbosity=2).run(suite)
-
--- a/MoinMoin/_tests/_test_template.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/_test_template.py	Fri Apr 20 00:12:50 2007 +0200
@@ -10,7 +10,6 @@
 
 import unittest
 from MoinMoin import module_tested
-from MoinMoin._tests import TestConfig
 
 
 class SimplestTestCase(unittest.TestCase):
@@ -52,9 +51,8 @@
 
         Some test needs specific config values, or they will fail.
         """
-        self.config = TestConfig(self.request,
-                                 defaults=['this option', 'that option'],
-                                 another_option='non default value')
+        self.config = self.TestConfig(defaults=['this option', 'that option'],
+                                      another_option='non default value')
 
     def tearDown(self):
         """ Stuff that should run after each test
--- a/MoinMoin/_tests/broken/test_converter_text_html_text_moin_wiki.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1137 +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
-from MoinMoin import _tests
-
-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 BaseTests(unittest.TestCase):
-
-    def setUp(self):
-        self.cfg = _tests.TestConfig(self.request, 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 ConvertBlockRepeatableTests(BaseTests):
-    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 ConvertInlineFormatRepeatableTests(BaseTests):
-    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 ConvertInlineItemRepeatableTests(BaseTests):
-    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 StripTests(unittest.TestCase):
-    def do(self, cls, text, output):
-        tree = converter.parse(text)
-        cls().do(tree)
-        out = StringIO()
-        try:
-            import xml.dom.ext
-        except ImportError:
-            raise _tests.TestSkiped('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 StripWhitespaceTests(StripTests):
-    def do(self, text, output):
-        super(StripWhitespaceTests, 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 ConvertBrokenBrowserTests(BaseTests):
-    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)
-
-if __name__ == '__main__':
-    unittest.main()
-
--- a/MoinMoin/_tests/broken/test_parser_text_moin_wiki.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,452 +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
-import re
-from StringIO import StringIO
-from MoinMoin._tests import TestConfig
-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 ParagraphsTestCase(ParserTestCase):
-    """ Test paragraphs creating
-
-    All tests ignoring white space in output
-    """
-
-    def testFirstParagraph(self):
-         """ parser.wiki: first paragraph should be in <p> """
-         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 """
-        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 """
-
-        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 HeadingsTestCase(ParserTestCase):
-    """ Test various heading problems """
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = TestConfig(self.request, 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.
-        """
-        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 TOCTestCase(ParserTestCase):
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = TestConfig(self.request, 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 DateTimeMacroTestCase(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 = TestConfig(self.request,
-                                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 TextFormatingTestCase(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 CloseInlineTestCase(ParserTestCase):
-
-    def testCloseOneInline(self):
-        """ parser.wiki: close open inline tag when block close """
-        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 InlineCrossingTestCase(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 EscapeHTMLTestCase(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 EscapeWikiTableMarkupTestCase(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 RuleTestCase(ParserTestCase):
-    """ Test rules markup """
-
-    def testNotRule(self):
-        """ parser.wiki: --- is no rule """
-        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 """
-        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 """
-
-        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 """
-        test = '-' * 254        
-        result = self.parse(test)
-        expected = '<hr class="hr6">'
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class BlockTestCase(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 """
-        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.
-        """
-        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())
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/compat.py	Fri Apr 20 00:12:50 2007 +0200
@@ -0,0 +1,61 @@
+""" UnitTest compatiblity code, from the py lib. MIT licensed originally, copyright Holger Krekel. """
+
+import py
+from py.__.test.outcome import Failed, Passed
+
+
+class TestCaseUnit(py.test.collect.Function):
+    """ compatibility Unit executor for TestCase methods
+        honouring setUp and tearDown semantics.
+    """
+    def execute(self, session):
+        boundmethod = self.obj 
+        instance = boundmethod.im_self 
+        instance.setUp()
+        try:
+            boundmethod()
+        finally:
+            instance.tearDown()
+        return Passed()
+
+class TestCase(object):
+    """compatibility class of unittest's TestCase. """
+    Function = TestCaseUnit
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def fail(self, msg=None):
+        """ fail immediate with given message. """
+        raise Failed(msg=msg)
+
+    def assertRaises(self, excclass, func, *args, **kwargs):
+        py.test.raises(excclass, func, *args, **kwargs)
+    failUnlessRaises = assertRaises
+
+    # dynamically construct (redundant) methods
+    aliasmap = [
+        ('x',   'not x', 'assert_, failUnless'),
+        ('x',   'x',     'failIf'),
+        ('x,y', 'x!=y',  'failUnlessEqual,assertEqual, assertEquals'),
+        ('x,y', 'x==y',  'failIfEqual,assertNotEqual, assertNotEquals'),
+        ]
+    items = []
+    for sig, expr, names in aliasmap:
+        names = map(str.strip, names.split(','))
+        sigsubst = expr.replace('y', '%s').replace('x', '%s')
+        for name in names:
+            items.append("""
+                def %(name)s(self, %(sig)s, msg=""):
+                    __tracebackhide__ = True
+                    if %(expr)s:
+                        raise Failed(msg=msg + (%(sigsubst)r %% (%(sig)s)))
+            """ % locals() )
+
+    source = "".join(items)
+    exec py.code.Source(source).compile()
+
+__all__ = ['TestCase']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/maketestwiki.py	Fri Apr 20 00:12:50 2007 +0200
@@ -0,0 +1,64 @@
+# -*- coding: iso-8859-1 -*-
+"""
+MoinMoin - make a test wiki
+
+Usage:
+
+    maketestwiki.py
+
+@copyright: 2005 by Thomas Waldmann
+@license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, shutil, errno, tarfile
+
+filename = globals().get("__file__") or sys.argv[0]
+moinpath = os.path.abspath(os.path.join(os.path.dirname(filename), os.pardir, os.pardir))
+sys.path.insert(0, moinpath)
+
+WIKI = os.path.abspath(os.path.join(moinpath, 'tests', 'wiki'))
+SHARE = os.path.abspath(os.path.join(moinpath, 'wiki'))
+
+
+def removeTestWiki():
+    print 'removing old wiki ...'
+    for dir in ['data', 'underlay']:
+        try:
+            shutil.rmtree(os.path.join(WIKI, dir))
+        except OSError, err:
+            if not (err.errno == errno.ENOENT or
+                    (err.errno == 3 and os.name == 'nt')):
+                raise
+
+
+def copyData():
+    print 'copying data ...'
+    src = os.path.join(SHARE, 'data')
+    dst = os.path.join(WIKI, 'data')
+    shutil.copytree(src, dst)
+
+
+def untarUnderlay():
+    print 'untaring underlay ...'
+    tar = tarfile.open(os.path.join(SHARE, 'underlay.tar.bz2'), mode='r:bz2')
+    for member in tar:
+        tar.extract(member, WIKI)
+    tar.close()
+
+
+def run(skip_if_existing=False):
+    try:
+        os.makedirs(WIKI)
+    except OSError, e:
+        if e.errno != errno.EEXIST:
+            raise
+
+    if skip_if_existing and os.path.exists(os.path.join(WIKI, 'data')):
+        return
+    removeTestWiki()
+    copyData()
+    untarUnderlay()
+
+if __name__ == '__main__':
+    run()
+
--- a/MoinMoin/_tests/test_Page.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_Page.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,7 +9,7 @@
 import unittest
 from MoinMoin import Page
 
-class existsTestCase(unittest.TestCase):
+class TestExists(unittest.TestCase):
     """Page: testing wiki page"""
 
     def testExists(self):
--- a/MoinMoin/_tests/test_PageEditor.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_PageEditor.py	Fri Apr 20 00:12:50 2007 +0200
@@ -7,12 +7,14 @@
 """
 
 import unittest
+
+import py
+
 from MoinMoin.Page import Page
 from MoinMoin.PageEditor import PageEditor
-from MoinMoin._tests import TestConfig, TestSkiped
 
 
-class ExpandVarsTestCase(unittest.TestCase):
+class TestExpandVars(unittest.TestCase):
     """PageEditor: testing page editor"""
 
     pagename = u'AutoCreatedMoinMoinTemporaryTestPage'
@@ -36,7 +38,7 @@
                 'Expected "%(expected)s" but got "%(result)s"' % locals())
 
 
-class ExpandUserNameTest(unittest.TestCase):
+class TestExpandUserName(unittest.TestCase):
     """ Base class for user name tests
     
     Set user name during tests.
@@ -56,7 +58,7 @@
         return self.page._expand_variables(self.variable)
 
 
-class ExpandCamelCaseName(ExpandUserNameTest):
+class TestExpandCamelCaseName(TestExpandUserName):
 
     name = u'UserName'
 
@@ -65,34 +67,34 @@
         self.assertEqual(self.expand(), self.name)
 
 
-class ExpandExtendedName(ExpandUserNameTest):
+class TestExpandExtendedName(TestExpandUserName):
 
     name = u'user name'
 
     def testExtendedNamesEnabled(self):
         """ PageEditor: expand @USERNAME@ extended name - enabled """
         try:
-            config = TestConfig(self.request)
+            config = self.TestConfig()
             self.assertEqual(self.expand(), u'["%s"]' % self.name)
         finally:
             del config
 
 
-class ExpandMailto(ExpandUserNameTest):
+class TestExpandMailto(TestExpandUserName):
 
     variable = u'@MAILTO@'
     name = u'user name'
     email = 'user@example.com'
 
     def setUp(self):
-        ExpandUserNameTest.setUp(self)
+        TestExpandUserName.setUp(self)
         self.savedValid = self.request.user.valid
         self.request.user.valid = 1
         self.savedEmail = self.request.user.email
         self.request.user.email = self.email
 
     def tearDown(self):
-        ExpandUserNameTest.tearDown(self)
+        TestExpandUserName.tearDown(self)
         self.request.user.valid = self.savedValid
         self.request.user.email = self.savedEmail
 
@@ -101,7 +103,7 @@
         self.assertEqual(self.expand(), u'[[MailTo(%s)]]' % self.email)
 
 
-class ExpandPrivateVariables(ExpandUserNameTest):
+class TestExpandPrivateVariables(TestExpandUserName):
 
     variable = u'@ME@'
     name = u'AutoCreatedMoinMoinTemporaryTestUser'
@@ -109,14 +111,14 @@
     shouldDeleteTestPage = True
 
     def setUp(self):
-        ExpandUserNameTest.setUp(self)
+        TestExpandUserName.setUp(self)
         self.savedValid = self.request.user.valid
         self.request.user.valid = 1
         self.createTestPage()
         self.deleteCaches()
 
     def tearDown(self):
-        ExpandUserNameTest.tearDown(self)
+        TestExpandUserName.tearDown(self)
         self.request.user.valid = self.savedValid
         self.deleteTestPage()
 
@@ -135,8 +137,7 @@
         path = self.dictPagePath()
         if os.path.exists(path):
             self.shouldDeleteTestPage = False
-            raise TestSkiped("%s exists. Won't overwrite exiting page" %
-                             self.dictPage)
+            py.test.skip("%s exists. Won't overwrite exiting page" % self.dictPage)
         try:
             os.mkdir(path)
             revisionsDir = os.path.join(path, 'revisions')
@@ -146,7 +147,7 @@
             text = u' ME:: %s\n' % self.name
             file(os.path.join(revisionsDir, current), 'w').write(text)
         except Exception, err:
-            raise TestSkiped("Can not be create test page: %s" % err)
+            py.test.skip("Can not be create test page: %s" % err)
 
     def deleteCaches(self):
         """ Force the wiki to scan the test page into the dicts """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/test_converter_text_html_text_moin_wiki.py	Fri Apr 20 00:12:50 2007 +0200
@@ -0,0 +1,1139 @@
+# -*- 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
+
+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)
+
+if __name__ == '__main__':
+    unittest.main()
+
--- a/MoinMoin/_tests/test_error.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_error.py	Fri Apr 20 00:12:50 2007 +0200
@@ -8,10 +8,9 @@
 
 import unittest
 from MoinMoin import error
-from MoinMoin._tests import TestConfig
 
 
-class EncodingTestCase(unittest.TestCase):
+class TestEncoding(unittest.TestCase):
     """ MoinMoin errors do work with unicode transparently """
 
     def testCreateWithUnicode(self):
--- a/MoinMoin/_tests/test_formatter.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_formatter.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,12 +9,11 @@
 from unittest import TestCase
 import re
 
-from MoinMoin._tests import TestConfig
 from MoinMoin.Page import Page
 from MoinMoin import wikiutil
 
 
-class FormatterTestCase(TestCase):
+class TestFormatter(TestCase):
     def testSyntaxReference(self):
         formatters = wikiutil.getPlugins("formatter", self.request.cfg)
         for f_name in formatters:
--- a/MoinMoin/_tests/test_i18n.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.i18n Tests
-
-    @copyright: 2003-2004 by Juergen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest
-from MoinMoin import i18n
-
-class WhateverTestCase(unittest.TestCase):
-    """... tests"""
-    pass
--- a/MoinMoin/_tests/test_macro.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_macro.py	Fri Apr 20 00:12:50 2007 +0200
@@ -14,7 +14,7 @@
 from MoinMoin.formatter.text_html import Formatter
 
 
-class MacroTestCase(unittest.TestCase):
+class TestMacro(unittest.TestCase):
     def testTrivialMacro(self):
         """macro: trivial macro works"""
         m = self._make_macro()
--- a/MoinMoin/_tests/test_mail_sendmail.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_mail_sendmail.py	Fri Apr 20 00:12:50 2007 +0200
@@ -13,7 +13,7 @@
 from MoinMoin import config
 
 
-class decodeSpamSafeEmailTestCase(unittest.TestCase):
+class TestdecodeSpamSafeEmail(unittest.TestCase):
     """mail.sendmail: testing mail"""
 
     _tests = (
@@ -45,7 +45,7 @@
                              locals())
 
 
-class EncodeAddressTests(unittest.TestCase):
+class TestEncodeAddress(unittest.TestCase):
     """ Address encoding tests
     
     See http://www.faqs.org/rfcs/rfc2822.html section 3.4. 
--- a/MoinMoin/_tests/test_packages.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_packages.py	Fri Apr 20 00:12:50 2007 +0200
@@ -7,11 +7,14 @@
 """
 
 from unittest import TestCase
+
+import py
+
 from MoinMoin.Page import Page
-from MoinMoin._tests import TestConfig
-from MoinMoin._tests import TestSkiped as TestSkipped
+from MoinMoin.PageEditor import PageEditor
 from MoinMoin.packages import Package, ScriptEngine, MOIN_PACKAGE_FILE, packLine, unpackLine
 
+
 class DebugPackage(Package, ScriptEngine):
     """ Used for debugging, does not need a real .zip file. """
     def __init__(self, request, filename, script=None):
@@ -43,13 +46,13 @@
     def isPackage(self):
         return True
 
-class UnsafePackageTestcase(TestCase):
+class TestUnsafePackage(TestCase):
     """ Tests various things in the packages package. Note that this package does
         not care to clean up and needs to run in a test wiki because of that. """
 
     def setUp(self):
         if not getattr(self.request.cfg, 'is_test_wiki', False):
-            raise TestSkipped('This test needs to be run using the test wiki.')
+            py.test.skip('This test needs to be run using the test wiki.')
 
     def testBasicPackageThings(self):
         myPackage = DebugPackage(self.request, 'test')
@@ -59,7 +62,12 @@
         self.assertEqual(testseite2.getPageText(), "Hello world, I am the file testdatei")
         self.assert_(testseite2.isUnderlayPage())
 
-class QuotingTestCase(TestCase):
+    def tearDown(self):
+        DebugPackage(self.request, u"""moinmoinpackage|1
+DeletePage|FooPage|Test ...
+""").installPackage()
+
+class TestQuoting(TestCase):
     def testQuoting(self):
         for line in ([':foo', 'is\\', 'ja|', u't|ü', u'baAzß'], [], ['', '']):
             self.assertEqual(line, unpackLine(packLine(line)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/test_parser_text_moin_wiki.py	Fri Apr 20 00:12:50 2007 +0200
@@ -0,0 +1,464 @@
+# -*- 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
+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())
+
+
--- a/MoinMoin/_tests/test_pysupport.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_pysupport.py	Fri Apr 20 00:12:50 2007 +0200
@@ -7,11 +7,13 @@
 """
 
 import unittest, os, errno
+
+import py
+
 from MoinMoin.util import pysupport
-from MoinMoin._tests import TestSkiped
 
 
-class ImportNameFromMoinTestCase(unittest.TestCase):
+class TestImportNameFromMoin(unittest.TestCase):
     """ Test importName of MoinMoin modules
 
     We don't make any testing for files, assuming that moin package is
@@ -35,7 +37,7 @@
         self.failUnless(Parser is text_moin_wiki.Parser)
 
 
-class ImportNameFromPlugin(unittest.TestCase):
+class TestImportNameFromPlugin(unittest.TestCase):
     """ Base class for import plugin tests """
 
     name = 'Parser'
@@ -49,7 +51,7 @@
     def checkPackage(self, path):
         for item in (path, os.path.join(path, '__init__.py')):
             if not os.path.exists(item):
-                raise TestSkiped("Missing or wrong permissions: %s" % item)
+                py.test.skip("Missing or wrong permissions: %s" % item)
 
     def pluginExists(self):
         return (os.path.exists(self.pluginFilePath('.py')) or
@@ -59,19 +61,19 @@
         return os.path.join(self.pluginDirectory, self.plugin + suffix)
 
 
-class ImportNonExisiting(ImportNameFromPlugin):
+class TestImportNonExisiting(TestImportNameFromPlugin):
 
     plugin = 'NonExistingWikiPlugin'
 
     def testNonEsisting(self):
         """ pysupport: import nonexistent wiki plugin fail """
         if self.pluginExists():
-            raise TestSkiped('plugin exists: %s' % self.plugin)
+            py.test.skip('plugin exists: %s' % self.plugin)
         self.assertRaises(ImportError, pysupport.importName,
                           self.pluginModule, self.name)
 
 
-class ImportExisting(ImportNameFromPlugin):
+class TestImportExisting(TestImportNameFromPlugin):
 
     plugin = 'AutoCreatedMoinMoinTestPlugin'
     shouldDeleteTestPlugin = True
@@ -97,8 +99,7 @@
         """ Create test plugin, skiping if plugin exists """
         if self.pluginExists():
             self.shouldDeleteTestPlugin = False
-            raise TestSkiped("Won't overwrite exiting plugin: %s" %
-                             self.plugin)
+            py.test.skip("Won't overwrite exiting plugin: %s" % self.plugin)
         data = '''
 # If you find this file in your wiki plugin directory, you can safely
 # delete it.
@@ -110,7 +111,7 @@
         try:
             file(self.pluginFilePath('.py'), 'w').write(data)
         except Exception, err:
-            raise TestSkiped("Can't create test plugin: %s" % str(err))
+            py.test.skip("Can't create test plugin: %s" % str(err))
 
     def deleteTestPlugin(self):
         """ Delete plugin files ignoring missing files errors """
--- a/MoinMoin/_tests/test_request.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_request.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,10 +9,9 @@
 """
 
 import unittest
-from MoinMoin._tests import TestConfig
 from MoinMoin import config
 
-class NormalizePagenameTestCase(unittest.TestCase):
+class TestNormalizePagename(unittest.TestCase):
 
     def testPageInvalidChars(self):
         """ request: normalize pagename: remove invalid unicode chars
@@ -77,10 +76,10 @@
                              locals())
 
 
-class GroupPagesTestCase(unittest.TestCase):
+class TestGroupPages(unittest.TestCase):
 
     def setUp(self):
-        self.config = TestConfig(self.request, page_group_regex=r'.+Group')
+        self.config = self.TestConfig(page_group_regex=r'.+Group')
 
     def tearDown(self):
         del self.config
@@ -107,7 +106,7 @@
                              locals())
 
 
-class HTTPDateTests(unittest.TestCase):
+class TestHTTPDate(unittest.TestCase):
 
     def testRFC1123Date(self):
         """ request: httpDate default rfc1123 """
--- a/MoinMoin/_tests/test_search.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_search.py	Fri Apr 20 00:12:50 2007 +0200
@@ -10,7 +10,7 @@
 from MoinMoin import search
 
 
-class QuotingBugTests(unittest.TestCase):
+class TestQuotingBug(unittest.TestCase):
     """search: quoting bug tests 
     
     http://moinmoin.wikiwikiweb.de/MoinMoinBugs/SearchOneCharString
--- a/MoinMoin/_tests/test_security.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_security.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,16 +9,14 @@
 """
 
 import unittest
-from MoinMoin._tests import TestConfig
-from MoinMoin import security, _tests
+from MoinMoin import security
 
 acliter = security.ACLStringIterator
 
-class ACLStringIteratorTestCase(unittest.TestCase):
+class TestACLStringIterator(unittest.TestCase):
 
     def setUp(self):
-        self.config = TestConfig(self.request,
-                                 defaults=['acl_rights_valid', 'acl_rights_before'])
+        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
     def tearDown(self):
         del self.config
 
@@ -179,14 +177,14 @@
         self.assertEqual(rights, [])
 
 
-class AclTestCase(unittest.TestCase):
+class TestAcl(unittest.TestCase):
     """ security: testing access control list
 
     TO DO: test unknown user?
     """
     def setUp(self):
         # Backup user
-        self.config = TestConfig(self.request, defaults=['acl_rights_valid', 'acl_rights_before'])
+        self.config = self.TestConfig(defaults=['acl_rights_valid', 'acl_rights_before'])
         self.savedUser = self.request.user.name
 
     def tearDown(self):
--- a/MoinMoin/_tests/test_user.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_user.py	Fri Apr 20 00:12:50 2007 +0200
@@ -8,11 +8,13 @@
 
 import unittest, os
 
-from MoinMoin._tests import TestConfig, TestSkipped
+import py
+
 from MoinMoin import user, caching
 from MoinMoin.util import filesys
 
-class EncodePasswordTestCase(unittest.TestCase):
+
+class TestEncodePassword(unittest.TestCase):
     """user: encode passwords tests"""
 
     def testAscii(self):
@@ -35,7 +37,7 @@
                          'Expected "%(expected)s" but got "%(result)s"' % locals())
 
 
-class LoginWithPasswordTestCase(unittest.TestCase):
+class TestLoginWithPassword(unittest.TestCase):
     """user: login tests"""
 
     def setUp(self):
@@ -153,8 +155,7 @@
         # Validate that we are not modifying existing user data file!
         if self.user.exists():
             self.user = None
-            raise TestSkipped("Test user exists, will not override existing"
-                              " user data file!")
+            py.test.skip("Test user exists, will not override existing user data file!")
 
         # Save test user
         self.user.save()
@@ -162,14 +163,13 @@
         # Validate user creation
         if not self.user.exists():
             self.user = None
-            raise TestSkipped("Can't create test user")
+            py.test.skip("Can't create test user")
 
 
-class GroupNameTestCase(unittest.TestCase):
+class TestGroupName(unittest.TestCase):
 
     def setUp(self):
-        self.config = TestConfig(self.request,
-                                 page_group_regex=r'.+Group')
+        self.config = self.TestConfig(page_group_regex=r'.+Group')
 
     def tearDown(self):
         del self.config
@@ -187,7 +187,7 @@
                         'Expected "%(expected)s" but got "%(result)s"' % locals())
 
 
-class IsValidNameTestCase(unittest.TestCase):
+class TestIsValidName(unittest.TestCase):
 
     def testNonAlnumCharacters(self):
         """ user: isValidName: reject unicode non alpha numeric characters
--- a/MoinMoin/_tests/test_util_lock.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_util_lock.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,11 +9,13 @@
 """
 
 import unittest, tempfile, os, time, shutil
-from MoinMoin._tests import TestConfig, TestSkiped
+
+import py
+
 from MoinMoin.util.lock import ExclusiveLock
 
 
-class ExclusiveLockTests(unittest.TestCase):
+class TestExclusiveLock(unittest.TestCase):
     
     def setUp(self):
         self.test_dir = tempfile.mkdtemp('', 'lock_')
@@ -57,7 +59,7 @@
         """
         lock = ExclusiveLock(self.lock_dir)
         if not lock.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         lock.release()
         self.failUnless(lock.acquire(0.1), 
                         "Could not acquire lock after release")
@@ -66,7 +68,7 @@
         """ util.lock: ExclusiveLock: isLocked """
         lock = ExclusiveLock(self.lock_dir)
         if not lock.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         self.failUnless(lock.isLocked(), "lock state wrong")
         lock.release()
         self.failIf(lock.isLocked(), "lock state wrong")
@@ -75,7 +77,7 @@
         """ util.lock: ExclusiveLock: exists """
         lock = ExclusiveLock(self.lock_dir)
         if not lock.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         self.failUnless(lock.exists(), "lock should exists")
 
     def testIsExpired(self):
@@ -83,7 +85,7 @@
         timeout = 2.0
         lock = ExclusiveLock(self.lock_dir, timeout=timeout)
         if not lock.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         self.failIf(lock.isExpired(), "lock should not be expired yet")
         time.sleep(timeout)
         self.failUnless(lock.isExpired(), "lock should be expired")
@@ -93,7 +95,7 @@
         timeout = 2.0
         lock = ExclusiveLock(self.lock_dir, timeout=timeout)
         if not lock.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         self.failIf(lock.expire(), "lock should not be expired yet")
         time.sleep(timeout)
         self.failUnless(lock.expire(), "lock should be expired")
@@ -103,7 +105,7 @@
         first = ExclusiveLock(self.lock_dir)
         second = ExclusiveLock(self.lock_dir)
         if not first.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         self.failIf(second.acquire(0.1), "first lock is not exclusive")                
 
     def testAcquireAfterTimeout(self):
@@ -115,9 +117,9 @@
         first = ExclusiveLock(self.lock_dir, timeout)
         second = ExclusiveLock(self.lock_dir, timeout)
         if not first.acquire(0.1):
-            raise TestSkiped("can't acquire lock")
+            py.test.skip("can't acquire lock")
         if second.acquire(0.1):
-            raise TestSkiped("first lock is not exclusive")
+            py.test.skip("first lock is not exclusive")
         # Second lock should be acquired after timeout
         self.failUnless(second.acquire(timeout + 0.1), 
                         "can't acquire after timeout")
--- a/MoinMoin/_tests/test_util_web.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_util_web.py	Fri Apr 20 00:12:50 2007 +0200
@@ -12,7 +12,7 @@
 from MoinMoin.widget import html
 
 
-class MakeQueryStringTestCase(unittest.TestCase):
+class TestMakeQueryString(unittest.TestCase):
     """util.web: making query string"""
 
     def testMakeQueryStringFromArgument(self):
@@ -56,7 +56,7 @@
                               'but got "%(result)s"') % locals())
         
 
-class MakeSelectionTestCase(unittest.TestCase):
+class TestMakeSelection(unittest.TestCase):
     """util.web: creating html select"""
 
     values = ('one', 'two', 'simple', ('complex', 'A tuple & <escaped text>'))
--- a/MoinMoin/_tests/test_widget_html.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_widget_html.py	Fri Apr 20 00:12:50 2007 +0200
@@ -9,7 +9,7 @@
 import unittest
 from MoinMoin.widget import html
 
-class HTMLWidgetsTestCase(unittest.TestCase):
+class TestHTMLWidgets(unittest.TestCase):
     """widget.html: testing html widgets"""
 
     def testCreate(self):
--- a/MoinMoin/_tests/test_wikidicts.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_wikidicts.py	Fri Apr 20 00:12:50 2007 +0200
@@ -12,7 +12,7 @@
 from MoinMoin import wikidicts
 from MoinMoin import Page
 
-class GroupPageTestCase(unittest.TestCase):
+class TestGroupPage(unittest.TestCase):
 
     def testCamelCase(self):
         """ wikidicts: initFromText: CamelCase links """
@@ -68,7 +68,7 @@
         return group.members()
 
 
-class DictPageTestCase(unittest.TestCase):
+class TestDictPage(unittest.TestCase):
 
     def testGroupMembers(self):
         """ wikidicts: create dict from keys and values in text """
--- a/MoinMoin/_tests/test_wikisync.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_wikisync.py	Fri Apr 20 00:12:50 2007 +0200
@@ -8,20 +8,21 @@
 
 from unittest import TestCase
 
+import py
+
 from MoinMoin.PageEditor import PageEditor
-from MoinMoin._tests import TestConfig, TestSkipped
 
 from MoinMoin.wikisync import TagStore, BOTH
 
 
-class UnsafeSyncTestcase(TestCase):
+class TestUnsafeSync(TestCase):
     """ Tests various things related to syncing. Note that it is not possible
         to create pages without cluttering page revision currently, so we have to use
         the testwiki. """
 
     def setUp(self):
         if not getattr(self.request.cfg, 'is_test_wiki', False):
-            raise TestSkipped('This test needs to be run using the test wiki.')
+            py.test.skip('This test needs to be run using the test wiki.')
         self.page = PageEditor(self.request, "FrontPage")
 
     def testBasicTagThings(self):
--- a/MoinMoin/_tests/test_wikiutil.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_wikiutil.py	Fri Apr 20 00:12:50 2007 +0200
@@ -7,11 +7,10 @@
 """
 
 import unittest
-from MoinMoin._tests import TestConfig
 from MoinMoin import wikiutil
 
 
-class SystemPageTestCase(unittest.TestCase):
+class TestSystemPage(unittest.TestCase):
     systemPages = (
         # First level, on SystemPagesGroup
         'SystemPagesInEnglishGroup',
@@ -33,7 +32,7 @@
                 '"%(name)s" is NOT a system page' % locals())
 
 
-class TemplatePageTestCase(unittest.TestCase):
+class TestTemplatePage(unittest.TestCase):
     good = (
         'aTemplate',
         'MyTemplate',
@@ -48,10 +47,9 @@
 
     # require default page_template_regex config
     def setUp(self):
-        self.config = TestConfig(self.request,
-                                 defaults=['page_template_regex'])
+        self.config = self.TestConfig(defaults=['page_template_regex'])
     def tearDown(self):
-        del self.config
+        self.config.restore()
 
     def testTemplatePage(self):
         """wikiutil: good template names accepted, bad rejected"""
--- a/MoinMoin/_tests/test_wikixml_marshal.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/MoinMoin/_tests/test_wikixml_marshal.py	Fri Apr 20 00:12:50 2007 +0200
@@ -10,7 +10,7 @@
 import array
 from MoinMoin.wikixml import marshal
 
-class MarshalTestCase(unittest.TestCase):
+class TestMarshal(unittest.TestCase):
     """Testing Marshal used for ...XXX"""
 
     class Data:
--- a/MoinMoin/action/test.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - test action
-
-    This action allows you to run some tests and show some data about your system.
-
-    If you don't want this action to be available due to system privacy reasons,
-    do this in your wiki/farm config:
-
-    actions_excluded = ["test"]
-    
-    @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
-                2006 MoinMoin:ThomasWaldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-import os, sys
-
-from MoinMoin import config, version
-from MoinMoin.action import ActionBase
-from MoinMoin.logfile import editlog, eventlog
-
-
-def runTest(request):
-    request.write('Release %s\n' % version.release)
-    request.write('Revision %s\n' % version.revision)
-    request.write('Python version %s\n' % sys.version)
-    request.write('Python installed to %s\n' % sys.exec_prefix)
-
-    # Try xml
-    try:
-        import xml
-        request.write('PyXML is %sinstalled\n' % ('NOT ', '')['_xmlplus' in xml.__file__])
-    except ImportError:
-        request.write('PyXML is missing\n')
-
-    request.write('Python Path:\n')
-    for path in sys.path:
-        request.write('   %s\n' % path)
-
-    # check if the request is a local one
-    import socket
-    local_request = (socket.getfqdn(request.server_name) == socket.getfqdn(request.remote_addr))
-
-    # check directories
-    request.write("Checking directories...\n")
-    dirs = [('data', request.cfg.data_dir),
-            ('user', request.cfg.user_dir),
-           ]
-    for name, path in dirs:
-        if not os.path.isdir(path):
-            request.write("*** %s directory NOT FOUND (set to '%s')\n" % (name, path))
-        elif not os.access(path, os.R_OK | os.W_OK | os.X_OK):
-            request.write("*** %s directory NOT ACCESSIBLE (set to '%s')\n" % (name, path))
-        else:
-            path = os.path.abspath(path)
-            request.write("    %s directory tests OK (set to '%s')\n" % (name, path))
-
-    # check eventlog access
-    log = eventlog.EventLog(request)
-    msg = log.sanityCheck()
-    if msg:
-        request.write("*** %s\n" % msg)
-
-    # check editlog access
-    log = editlog.EditLog(request)
-    msg = log.sanityCheck()
-    if msg:
-        request.write("*** %s\n" % msg)
-
-    # keep some values to ourselves
-    request.write("\nServer Environment:\n")
-    if local_request:
-        # print the environment, in case people use exotic servers with broken
-        # CGI APIs (say, M$ IIS), to help debugging those
-        keys = os.environ.keys()
-        keys.sort()
-        for key in keys:
-            request.write("    %s = %s" % (key, repr(os.environ[key])))
-    else:
-        request.write("    ONLY AVAILABLE FOR LOCAL REQUESTS ON THIS HOST!")
-
-    # run unit tests
-    request.write("\n\nUnit Tests:\n")
-
-    # The unit tests are diabled on servers using threads, beause they
-    # change request.cfg, which is now shared between threads.
-    # TODO: check if we can enable them back in a safe way
-    if config.use_threads:
-        request.write("    *** The unit tests are disabled when using multi "
-                      "threading ***")
-    else:
-        # TODO: do we need to hide the error when _tests can't be
-        # imported? It might make it hard to debug the tests package
-        # itself.
-        try:
-            from MoinMoin import _tests
-        except ImportError:
-            request.write("    *** The unit tests are not available ***")
-        else:
-            _tests.run(request)
-
-class test(ActionBase):
-    """ test and show info action
-
-    Note: the action name is the class name
-    """
-    def do_action(self):
-        """ run tests """
-        request = self.request
-        request.emit_http_headers(["Content-type: text/plain; charset=%s" % config.charset])
-        request.write('MoinMoin Diagnosis\n======================\n\n')
-        runTest(request)
-        return True, ""
-
-    def do_action_finish(self, success):
-        """ we don't want to do the default stuff, but just NOTHING """
-        pass
-
-def execute(pagename, request):
-    """ Glue code for actions """
-    test(pagename, request).render()
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/conftest.py	Fri Apr 20 00:12:50 2007 +0200
@@ -0,0 +1,197 @@
+# -*- coding: iso-8859-1 -*-
+"""
+MoinMoin Testing Framework
+--------------------------
+
+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_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.
+
+@copyright: 2005 Nir Soffer, 2007 Alexander Schremmer
+@license: GNU GPL, see COPYING for details.
+"""
+
+import atexit
+from inspect import isclass
+from sys import modules
+import sys
+
+import py
+
+
+rootdir = py.magic.autopath().dirpath()
+moindir = rootdir.join("..")
+
+sys.path.insert(0, str(moindir))
+from MoinMoin._tests import maketestwiki, compat
+modules["unittest"] = compat # evil hack
+
+sys.path.insert(0, str(moindir.join("tests")))
+
+
+coverage_modules = set()
+
+
+try:
+    """
+    This code adds support for coverage.py (see
+    http://nedbatchelder.com/code/modules/coverage.html).
+    It prints a coverage report for the modules specified in all
+    module globals (of the test modules) named "coverage_modules".
+    """
+
+    import coverage
+
+    def report_coverage():
+        coverage.stop()
+        module_list = [modules[mod] for mod in coverage_modules]
+        module_list.sort()
+        coverage.report(module_list)
+
+    def callback(option, opt_str, value, parser):
+        atexit.register(report_coverage)
+        coverage.erase()
+        coverage.start()
+
+
+    py.test.config.addoptions('MoinMoin options', py.test.config.Option('-C',
+        '--coverage', action='callback', callback=callback,
+        help='Output information about code coverage (slow!)'))
+
+except ImportError:
+    coverage = None
+
+
+def init_test_request(static_state=[False]):
+    from MoinMoin.request import CLI
+    from MoinMoin.user import User
+    if not static_state[0]:
+        maketestwiki.run(True)
+        static_state[0] = True
+    request = CLI.Request()
+    request.form = request.args = request.setup_args()
+    request.user = User(request)
+    return request
+
+
+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 
+    the default datetime_fmt.
+    
+    When you set custom values in a TestConfig, the previous values are saved,
+    and when the TestConfig is called specifically, they are restored automatically.
+    
+    Typical Usage
+    -------------
+    ::
+        class SomeTest:
+            def setUp(self):
+                self.config = self.TestConfig(defaults=key_list, key=value,...)
+            def tearDown(self):
+                self.config.restore()
+            def testSomething(self):
+                # test that needs those defaults and custom values
+    """
+
+    def __init__(self, request):
+        """ Create temporary configuration for a test 
+
+        @param request: current request
+        """
+        self.request = request
+        self.old = {}  # Old config values
+        self.new = []  # New added attributes
+
+    def __call__(self, defaults=(), **custom):
+        """ Initialise a temporary configuration for a test 
+
+        @param defaults: list of keys that should use the default value
+        @param custom: other keys using non default values, or new keys
+               that request.cfg does not have already
+        """
+        self.setDefaults(defaults)
+        self.setCustom(**custom)
+
+        return self
+
+    def setDefaults(self, defaults=()):
+        """ Set default values for keys in defaults list
+        
+        Non existing default will raise an AttributeError.
+        """
+        from MoinMoin.config import multiconfig
+        for key in defaults:
+            self._setattr(key, getattr(multiconfig.DefaultConfig, key))
+
+    def setCustom(self, **custom):
+        """ Set custom values """
+        for key, value in custom.items():
+            self._setattr(key, value)
+
+    def _setattr(self, key, value):
+        """ Set a new value for key saving new added keys """
+        if hasattr(self.request.cfg, key):
+            self.old[key] = getattr(self.request.cfg, key)
+        else:
+            self.new.append(key)
+        setattr(self.request.cfg, key, value)
+
+    def restore(self):
+        """ Restore previous request.cfg 
+        
+        Set old keys to old values and delete new keys.
+        """
+        for key, value in self.old.items():
+            setattr(self.request.cfg, key, value)
+        for key in self.new:
+            delattr(self.request.cfg, key)
+
+
+class Module(py.test.collect.Module):
+    def __init__(self, *args, **kwargs):
+        self.request = init_test_request()
+        super(Module, self).__init__(*args, **kwargs)
+
+    def run(self, *args, **kwargs):
+        if coverage is not None:
+            coverage_modules.update(getattr(self.obj, 'coverage_modules', []))
+        return super(Module, self).run(*args, **kwargs)
+
+    def join(self, name):
+        obj = getattr(self.obj, name)
+        if isclass(obj):
+            return MoinClassCollector(name, parent=self)
+        elif hasattr(obj, 'func_code'):
+            return MoinTestFunction(name, parent=self)
+
+
+class MoinTestFunction(py.test.collect.Function):
+    def execute(self, target, *args):
+        request = self.parent.request
+        co = target.func_code
+        if 'request' in co.co_varnames[:co.co_argcount]:
+            target(request, *args)
+        else:
+            target(*args)
+
+
+class MoinClassCollector(py.test.collect.Class):
+    Function = MoinTestFunction
+
+    def setup(self):
+        cls = self.obj
+        cls.request = self.parent.request
+        cls.TestConfig = TestConfig(cls.request)
+        super(MoinClassCollector, self).setup()
--- a/tests/make_test.out	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-removing old wiki ...
-copying data ...
-untaring underlay ...
-error: access error like a dict ... ok
-error: create with encoded string ... ok
-error: create with any object ... ok
-error: create with unicode ... ok
-testQuoting (MoinMoin._tests.test_packages.QuotingTestCase) ... ok
-testBasicPackageThings (MoinMoin._tests.test_packages.UnsafePackageTestcase) ... ok
-Page: page.exists() finds existing pages only ... ok
-PageEditor: expand @USERNAME@ CamelCase ... ok
-PageEditor: expand @USERNAME@ extended name - enabled ... ok
-PageEditor: expand @MAILTO@ ... ok
-PageEditor: expand user variables ... ok
-PageEditor: expand general variables ... ok
-pysupport: import existing wiki plugin ... ok
-pysupport: import name from existing module ... ok
-pysupport: import nonexistent attritbue raises AttributeError ... ok
-pysupport: import nonexistent module raises ImportError ... ok
-pysupport: import nonexistent wiki plugin fail ... ok
-request: getPageNameFromQueryString: ascii ... ok
-request: getPageNameFromQueryString: non ascii ... ok
-request: getPageNameFromQueryString: under_score ... ok
-request: normalize pagename: restrict groups to alpha numeric Unicode ... ok
-request: httpDate default rfc1123 ... ok
-request: httpDate rfc850 ... ok
-request: normalize pagename: normalize slashes ... ok
-request: normalize pagename: normalize whitespace ... ok
-request: normalize pagename: remove invalid unicode chars ... ok
-request: normalize pagename: underscore convert to spaces and normalized ... ok
-search: quoting bug - unquoted terms ... ok
-search: quoting bug - quoted terms ... ok
-user: encode ascii password ... ok
-user: encode unicode password ... ok
-user: isValidName: reject group names ... ok
-user: isValidName: reject unicode non alpha numeric characters ... ok
-user: isValidName: accept names in any language, with spaces ... ok
-user: isValidName: reject leading, trailing or multiple whitespace ... ok
-user: login with ascii password ... ok
-user: login with non-ascii password in pre 1.3 user file ... ok
-user: login replace old non-ascii password in pre 1.3 user file ... ok
-user: login with non-ascii password ... ok
-util.lock: ExclusiveLock: acquire ... ok
-util.lock: ExclusiveLock: acquire after timeout ... ok
-util.lock: ExclusiveLock: lock is exclusive ... ok
-util.lock: ExclusiveLock: exists ... ok
-util.lock: ExclusiveLock: expire ... ok
-util.lock: ExclusiveLock: isExpired ... ok
-util.lock: ExclusiveLock: isLocked ... ok
-util.lock: ExclusiveLock: release ... ok
-util.lock: ExclusiveLock: raise ValueError for timeout < 2.0 ... ok
-util.mail: encode address: 'Phrase <local@domain>' ... ok
-util.mail: encode Uncode address: 'ויקי <local@domain>' ... ok
-util.mail: encode address with empty address: 'Phrase <>' ... ok
-util.mail: encode address with empty phrase: '<local@domain>' ... ok
-util.mail: encode invalid address 'Phrase <blah' ... ok
-util.mail: encode simple address: local@domain ... ok
-util.mail: decoding spam safe mail ... ok
-util.web: make query sting from argument ... ok
-util.web: make query sting from argument and keywords ... ok
-util.web: make query sting from keywords ... ok
-util.web: creating html select with no selection ... ok
-util.web: creating html select with non existing selection ... ok
-util.web: creating html select with selected item ... ok
-widget.html: append to and extend composite element ... ok
-widget.html: creating html widgets ... ok
-widegt.html: invalid attributes raises exception ... ok
-wikiacl: allow extra white space between entries ... ok
-wikiacl: bad guy may not allowed anything ... ok
-wikiacl: default meta acl ... ok
-wikiacl: empty acl string raise StopIteration ... ok
-wikiacl: empty names with rights ... ok
-wikiacl: empty rights ... ok
-wikiacl: ignore rights not in acl_rights_valid ... ok
-wikiacl: ignore invalid acl ... ok
-wikiacl: mixed wiki names and names with spaces ... ok
-wikiacl: acl modifiers ... ok
-wikiacl: multiple entries ... ok
-wikiacl: multiple entries with spaces ... ok
-wikiacl: multiple names with spaces ... ok
-wikiacl: single name with spaces ... ok
-wikiacl: single wiki name, single right ... ok
-wikiacl: white space acl string raise StopIteration ... ok
-wikiacl: applying acl by user name ... ok
-wikidicts: create dict from keys and values in text ... ok
-wikidict: names in SystemPagesGroup should be in request.dicts ... ok
-wikidicts: initFromText: CamelCase links ... ok
-wikidicts: initFromText: extended link ... ok
-wikidicts: initFromText: extended names ... ok
-wikidicts: initFromText: ignore anything but first level list itmes ... ok
-wikidicts: initFromText: ignore non first level items ... ok
-wikidicts: initFromText: strip whitespace around items ... ok
-wikimacro: trivial macro works ... ok
-wikiutil: good system page names accepted, bad rejected ... ok
-wikiutil: good template names accepted, bad rejected ... ok
-wikixml.marshal: create new marshal ... ok
-wikixml.marshal: setting marshal property ... ok
-
-----------------------------------------------------------------------
-Ran 94 tests in 6.877s
-
-OK
--- a/tests/maketestwiki.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-MoinMoin - make a test wiki
-
-Usage:
-
-    maketestwiki.py
-
-@copyright: 2005 by Thomas Waldmann
-@license: GNU GPL, see COPYING for details.
-"""
-
-import os, sys, shutil, errno, tarfile
-
-moinpath = os.path.join(os.path.dirname(sys.argv[0]), os.pardir)
-sys.path.insert(0, os.path.abspath(moinpath))
-
-WIKI = os.path.abspath(os.path.join('tests', 'wiki'))
-SHARE = os.path.abspath('wiki')
-
-def removeTestWiki():
-    print 'removing old wiki ...'
-    for dir in ['data', 'underlay']:
-        try:
-            shutil.rmtree(os.path.join(WIKI, dir))
-        except OSError, err:
-            if not (err.errno == errno.ENOENT or
-                    (err.errno == 3 and os.name == 'nt')):
-                raise
-
-def copyData():
-    print 'copying data ...'
-    src = os.path.join(SHARE, 'data')
-    dst = os.path.join(WIKI, 'data')
-    shutil.copytree(src, dst)
-    # Remove arch-ids dirs
-    for path, dirs, files in os.walk(dst):
-        for dir in dirs[:]:
-            if dir == '.arch-ids':
-                shutil.rmtree(os.path.join(path, dir))
-                dirs.remove(dir)
-
-
-def untarUnderlay():
-    print 'untaring underlay ...'
-    tar = tarfile.open(os.path.join(SHARE, 'underlay.tar.bz2'), mode='r:bz2')
-    for member in tar:
-        tar.extract(member, WIKI)
-    tar.close()
-
-
-def run():
-    try:
-        os.makedirs(WIKI)
-    except OSError, e:
-        if e.errno != errno.EEXIST:
-            raise
-
-    removeTestWiki()
-    copyData()
-    untarUnderlay()
-
-if __name__ == '__main__':
-    run()
-
--- a/tests/runtests.py	Thu Apr 19 12:55:07 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-MoinMoin - Run Unit tests
-
-Usage:
-
-    runtests [test_name...]
-
-Without arguments run all the tests in the _tests package.
-
-@copyright: 2002-2004 by Jürgen Hermann <jh@web.de>
-@license: GNU GPL, see COPYING for details.
-"""
-
-import sys
-
-from MoinMoin import _tests
-
-def run():
-    _tests.run(names=sys.argv[1:])
-
-
-if __name__ == '__main__':
-    run()
-
--- a/tests/wikiconfig.py	Thu Apr 19 12:55:07 2007 +0200
+++ b/tests/wikiconfig.py	Fri Apr 20 00:12:50 2007 +0200
@@ -6,14 +6,19 @@
 @license: GNU GPL, see COPYING for details.
 """
 
+import os
+
 from MoinMoin.config.multiconfig import DefaultConfig
 
 
 class Config(DefaultConfig):
     sitename = u'Developer Test Wiki'
     logo_string = sitename
-    data_dir = './tests/wiki/data/'
-    data_underlay_dir = './tests/wiki/underlay/'
+
+    _base_dir = os.path.join(os.path.dirname(__file__), 'wiki')
+    data_dir = os.path.join(_base_dir, "data")
+    data_underlay_dir = os.path.join(_base_dir, "underlay")
+
     show_hosts = 1                  
     # used to check if it is really a wiki we may modify 
     is_test_wiki = True