Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/console.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/console.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/console.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/console.py 
Sat Nov 15 01:14:46 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2004-2009 Edgewall Software
+# Copyright (C) 2004-2013 Edgewall Software
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
@@ -14,6 +14,7 @@
 # Author: Tim Moloney <t.molo...@verizon.net>
 
 import difflib
+import inspect
 import os
 import re
 import sys
@@ -42,9 +43,14 @@ import trac.search.web_ui
 import trac.timeline.web_ui
 import trac.wiki.web_ui
 
-from trac.admin import console, console_date_format
+from trac.admin.api import AdminCommandManager, IAdminCommandProvider, \
+                           console_date_format, get_console_locale
+from trac.admin.console import TracAdmin, TracAdminHelpMacro
+from trac.core import Component, implements
 from trac.test import EnvironmentStub
-from trac.util.datefmt import format_date, get_date_format_hint
+from trac.util.datefmt import format_date, get_date_format_hint, \
+                              get_datetime_format_hint
+from trac.util.translation import get_available_locales, has_babel
 from trac.web.tests.session import _prep_session_table
 
 STRIP_TRAILING_SPACE = re.compile(r'( +)$', re.MULTILINE)
@@ -71,20 +77,50 @@ def load_expected_results(file, pattern)
     return expected
 
 
+def execute_cmd(tracadmin, cmd, strip_trailing_space=True, input=None):
+    _in = sys.stdin
+    _err = sys.stderr
+    _out = sys.stdout
+    try:
+        if input:
+            sys.stdin = StringIO(input.encode('utf-8'))
+            sys.stdin.encoding = 'utf-8' # fake input encoding
+        sys.stderr = sys.stdout = out = StringIO()
+        out.encoding = 'utf-8' # fake output encoding
+        retval = None
+        try:
+            retval = tracadmin.onecmd(cmd)
+        except SystemExit:
+            pass
+        value = out.getvalue()
+        if isinstance(value, str): # reverse what print_listing did
+            value = value.decode('utf-8')
+        if strip_trailing_space:
+            return retval, STRIP_TRAILING_SPACE.sub('', value)
+        else:
+            return retval, value
+    finally:
+        sys.stdin = _in
+        sys.stderr = _err
+        sys.stdout = _out
+
+
 class TracadminTestCase(unittest.TestCase):
     """
     Tests the output of trac-admin and is meant to be used with
     .../trac/tests.py.
     """
 
-    expected_results = load_expected_results(
-            os.path.join(os.path.split(__file__)[0], 'console-tests.txt'),
-            '===== (test_[^ ]+) =====')
+    expected_results_file = os.path.join(os.path.dirname(__file__),
+                                         'console-tests.txt')
+
+    expected_results = load_expected_results(expected_results_file,
+                                             '===== (test_[^ ]+) =====')
 
     def setUp(self):
         self.env = EnvironmentStub(default_data=True, enable=('trac.*',),
                                    disable=('trac.tests.*',))
-        self._admin = console.TracAdmin()
+        self._admin = TracAdmin()
         self._admin.env_set('', self.env)
 
         # Set test date to 11th Jan 2004
@@ -94,39 +130,32 @@ class TracadminTestCase(unittest.TestCas
         self.env = None
 
     def _execute(self, cmd, strip_trailing_space=True, input=None):
-        _in = sys.stdin
-        _err = sys.stderr
-        _out = sys.stdout
-        try:
-            if input:
-                sys.stdin = StringIO(input.encode('utf-8'))
-                sys.stdin.encoding = 'utf-8' # fake input encoding
-            sys.stderr = sys.stdout = out = StringIO()
-            out.encoding = 'utf-8' # fake output encoding
-            retval = None
-            try:
-                retval = self._admin.onecmd(cmd)
-            except SystemExit:
-                pass
-            value = out.getvalue()
-            if isinstance(value, str): # reverse what print_listing did
-                value = value.decode('utf-8')
-            # DEBUG: uncomment in case of `AssertionError: 0 != 2` in tests
-            #if retval != 0:
-            #    print>>_err, value
-            if strip_trailing_space:
-                return retval, STRIP_TRAILING_SPACE.sub('', value)
-            else:
-                return retval, value
-        finally:
-            sys.stdin = _in
-            sys.stderr = _err
-            sys.stdout = _out
-
-    def assertEqual(self, expected_results, output):
-        if not (isinstance(expected_results, basestring) and \
+        return execute_cmd(self._admin, cmd,
+                           strip_trailing_space=strip_trailing_space,
+                           input=input)
+
+    @property
+    def _datetime_format_hint(self):
+        return get_datetime_format_hint(get_console_locale(self.env))
+
+    def _get_command_help(self, *args):
+        docs = AdminCommandManager(self.env).get_command_help(list(args))
+        self.assertEqual(1, len(docs))
+        return docs[0][2]
+
+    def assertExpectedResult(self, output, args=None):
+        test_name = inspect.stack()[1][3]
+        expected_result = self.expected_results[test_name]
+        if args is not None:
+            expected_result %= args
+        self.assertEqual(expected_result, output)
+
+    def assertEqual(self, expected_results, output, msg=None):
+        """:deprecated: since 1.0.2, use `assertExpectedResult` instead."""
+        if not (isinstance(expected_results, basestring) and
                 isinstance(output, basestring)):
-            return unittest.TestCase.assertEqual(self, expected_results, 
output)
+            return unittest.TestCase.assertEqual(self, expected_results,
+                                                 output, msg)
         def diff():
             # Create a useful delta between the output and the expected output
             output_lines = ['%s\n' % x for x in output.split('\n')]
@@ -153,13 +182,69 @@ class TracadminTestCase(unittest.TestCas
         """
         from trac import __version__
 
-        test_name = sys._getframe().f_code.co_name
-        d = {'version': __version__,
-             'date_format_hint': get_date_format_hint()}
-        expected_results = self.expected_results[test_name] % d
         rv, output = self._execute('help')
-        self.assertEqual(0, rv)
-        self.assertEqual(expected_results, output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output, {
+            'version': __version__,
+            'date_format_hint': get_date_format_hint()
+        })
+        self.assertTrue(all(len(line) < 80 for line in output.split('\n')),
+                        "Lines should be less than 80 characters in length.")
+
+    # Locale test
+
+    def _test_get_console_locale_with_babel(self):
+        from babel.core import Locale, UnknownLocaleError
+        locales = get_available_locales()
+        en_US = Locale.parse('en_US')
+        de = Locale.parse('de')
+        de_DE = Locale.parse('de_DE')
+        try:
+            default = Locale.default()
+        except UnknownLocaleError:
+            default = None
+
+        language = self.env.config.get('trac', 'default_language')
+        try:
+            self.assertEqual(default, get_console_locale(None, None))
+            self.env.config.set('trac', 'default_language', '')
+            if 'de' in locales:
+                self.assertEqual(de, get_console_locale(None, 'de_DE.UTF8'))
+                self.env.config.set('trac', 'default_language', 'de')
+                self.assertEqual(de, get_console_locale(self.env, None))
+                self.assertEqual(de, get_console_locale(self.env, 'C'))
+                self.env.config.set('trac', 'default_language', 'en_US')
+                self.assertEqual(en_US, get_console_locale(self.env, None))
+                self.assertEqual(en_US, get_console_locale(self.env, 'C'))
+                self.assertEqual(de, get_console_locale(self.env,
+                                                        'de_DE.UTF8'))
+            if not locales:  # compiled catalog is missing
+                self.assertEqual(default, get_console_locale(None,
+                                                             'de_DE.UTF8'))
+                self.env.config.set('trac', 'default_language', 'de')
+                self.assertEqual(default, get_console_locale(self.env, None))
+                self.assertEqual(default, get_console_locale(self.env, 'C'))
+                self.env.config.set('trac', 'default_language', 'en_US')
+                self.assertEqual(en_US, get_console_locale(self.env, None))
+                self.assertEqual(en_US, get_console_locale(self.env, 'C'))
+                self.assertEqual(en_US, get_console_locale(self.env,
+                                                           'de_DE.UTF8'))
+        finally:
+            self.env.config.set('trac', 'default_language', language)
+
+    def _test_get_console_locale_without_babel(self):
+        self.assertEqual(None, get_console_locale(None, 'en_US.UTF8'))
+        language = self.env.config.get('trac', 'default_language')
+        try:
+            self.env.config.set('trac', 'default_language', 'en_US')
+            self.assertEqual(None, get_console_locale(self.env, 'en_US.UTF8'))
+        finally:
+            self.env.config.set('trac', 'default_language', language)
+
+    if has_babel:
+        test_get_console_locale = _test_get_console_locale_with_babel
+    else:
+        test_get_console_locale = _test_get_console_locale_without_babel
 
     # Attachment tests
 
@@ -172,10 +257,17 @@ class TracadminTestCase(unittest.TestCas
         #        commands. This requires being able to control the current
         #        time, which in turn would require centralizing the time
         #        provider, for example in the environment object.
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('attachment list wiki:WikiStart')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_attachment_add_nonexistent_resource(self):
+        """Tests the 'attachment add' command in trac-admin, on a non-existent
+        resource."""
+        rv, output = self._execute('attachment add wiki:NonExistentPage %s'
+                                   % __file__)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Config tests
 
@@ -184,21 +276,19 @@ class TracadminTestCase(unittest.TestCas
         Tests the 'config get' command in trac-admin.  This particular
         test gets the project name from the config.
         """
-        test_name = sys._getframe().f_code.co_name
         self.env.config.set('project', 'name', 'Test project')
         rv, output = self._execute('config get project name')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_config_set(self):
         """
         Tests the 'config set' command in trac-admin.  This particular
         test sets the project name using an option value containing a space.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('config set project name "Test project"')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
         self.assertEqual('Test project',
                          self.env.config.get('project', 'name'))
 
@@ -208,11 +298,10 @@ class TracadminTestCase(unittest.TestCas
         test removes the project name from the config, therefore reverting
         the option to the default value.
         """
-        test_name = sys._getframe().f_code.co_name
         self.env.config.set('project', 'name', 'Test project')
         rv, output = self._execute('config remove project name')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
         self.assertEqual('My Project', self.env.config.get('project', 'name'))
 
     # Permission tests
@@ -223,10 +312,9 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_add_one_action_ok(self):
         """
@@ -234,11 +322,10 @@ class TracadminTestCase(unittest.TestCas
         test passes valid arguments to add one permission and checks for
         success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission add test_user WIKI_VIEW')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_add_multiple_actions_ok(self):
         """
@@ -246,11 +333,10 @@ class TracadminTestCase(unittest.TestCas
         test passes valid arguments to add multiple permissions and checks for
         success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission add test_user LOG_VIEW FILE_VIEW')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_add_already_exists(self):
         """
@@ -258,13 +344,12 @@ class TracadminTestCase(unittest.TestCas
         test passes a permission that already exists and checks for the
         message. Other permissions passed are added.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('permission add anonymous WIKI_CREATE '
                                    'WIKI_VIEW WIKI_MODIFY')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output2 = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output + output2)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output + output2)
 
     def test_permission_remove_one_action_ok(self):
         """
@@ -272,11 +357,10 @@ class TracadminTestCase(unittest.TestCas
         test passes valid arguments to remove one permission and checks for
         success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission remove anonymous TICKET_MODIFY')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_remove_multiple_actions_ok(self):
         """
@@ -284,44 +368,40 @@ class TracadminTestCase(unittest.TestCas
         test passes valid arguments to remove multiple permission and checks
         for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission remove anonymous WIKI_CREATE WIKI_MODIFY')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_remove_all_actions_for_user(self):
         """
         Tests the 'permission remove' command in trac-admin.  This particular
         test removes all permissions for anonymous.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission remove anonymous *')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_remove_action_for_all_users(self):
         """
         Tests the 'permission remove' command in trac-admin.  This particular
         test removes the TICKET_CREATE permission from all users.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('permission add anonymous TICKET_CREATE')
         self._execute('permission remove * TICKET_CREATE')
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_remove_unknown_user(self):
         """
         Tests the 'permission remove' command in trac-admin.  This particular
         test tries removing a permission from an unknown user.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('permission remove joe TICKET_VIEW')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_remove_action_not_granted(self):
         """
@@ -329,38 +409,45 @@ class TracadminTestCase(unittest.TestCas
         test tries removing TICKET_CREATE from user anonymous, who doesn't
         have that permission.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('permission remove anonymous TICKET_CREATE')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_permission_remove_action_granted_through_meta_permission(self):
+        """
+        Tests the 'permission remove' command in trac-admin.  This particular
+        test tries removing WIKI_VIEW from a user. WIKI_VIEW has been granted
+        through user anonymous."""
+        self._execute('permission add joe TICKET_VIEW')
+        rv, output = self._execute('permission remove joe WIKI_VIEW')
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_export_ok(self):
         """
         Tests the 'permission export' command in trac-admin.  This particular
         test exports the default permissions to stdout.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('permission export')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_permission_import_ok(self):
         """
         Tests the 'permission import' command in trac-admin.  This particular
         test exports additional permissions, removes them and imports them 
back.
         """
-        test_name = sys._getframe().f_code.co_name
         user = u'test_user\u0250'
         self._execute('permission add ' + user + ' WIKI_VIEW')
         self._execute('permission add ' + user + ' TICKET_VIEW')
         rv, output = self._execute('permission export')
         self._execute('permission remove ' + user + ' *')
         rv, output = self._execute('permission import', input=output)
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         self.assertEqual('', output)
         rv, output = self._execute('permission list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     # Component tests
 
@@ -370,21 +457,30 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_add_ok(self):
         """
         Tests the 'component add' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
+        self._execute('component add new_component')
+        rv, output = self._execute('component list')
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_component_add_optional_owner_ok(self):
+        """
+        Tests the 'component add' command in trac-admin with the optional
+        'owner' argument.  This particular test passes valid arguments and
+        checks for success.
+        """
         self._execute('component add new_component new_user')
         rv, output = self._execute('component list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_add_error_already_exists(self):
         """
@@ -392,52 +488,47 @@ class TracadminTestCase(unittest.TestCas
         test passes a component name that already exists and checks for an
         error message.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component add component1 new_user')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_rename_ok(self):
         """
         Tests the 'component rename' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('component rename component1 changed_name')
         rv, output = self._execute('component list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_rename_error_bad_component(self):
         """
         Tests the 'component rename' command in trac-admin.  This particular
         test tries to rename a component that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component rename bad_component 
changed_name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_rename_error_bad_new_name(self):
         """
         Tests the 'component rename' command in trac-admin.  This particular
         test tries to rename a component to a name that already exists.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component rename component1 component2')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_chown_ok(self):
         """
         Tests the 'component chown' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('component chown component2 changed_owner')
         rv, output = self._execute('component list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_chown_error_bad_component(self):
         """
@@ -445,34 +536,28 @@ class TracadminTestCase(unittest.TestCas
         test tries to change the owner of a component that does not
         exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component chown bad_component 
changed_owner')
-        self.assertEqual(2, rv)
-        # We currently trigger a deprecation warning with py26 so we
-        # can currrently only verify that the end of the output string is
-        # correct
-        self.assertEqual(output.endswith(self.expected_results[test_name]), 
True)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_remove_ok(self):
         """
         Tests the 'component remove' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('component remove component1')
         rv, output = self._execute('component list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_component_remove_error_bad_component(self):
         """
         Tests the 'component remove' command in trac-admin.  This particular
         test tries to remove a component that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('component remove bad_component')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Ticket-type tests
 
@@ -482,21 +567,19 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_add_ok(self):
         """
         Tests the 'ticket_type add' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('ticket_type add new_type')
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_add_error_already_exists(self):
         """
@@ -504,94 +587,85 @@ class TracadminTestCase(unittest.TestCas
         test passes a ticket type that already exists and checks for an error
         message.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type add defect')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_change_ok(self):
         """
         Tests the 'ticket_type change' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('ticket_type change defect bug')
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_change_error_bad_type(self):
         """
         Tests the 'ticket_type change' command in trac-admin.  This particular
         test tries to change a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type change bad_type changed_type')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_change_error_bad_new_name(self):
         """
         Tests the 'ticket_type change' command in trac-admin.  This particular
         test tries to change a ticket type to another type that already exists.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type change defect task')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_remove_ok(self):
         """
         Tests the 'ticket_type remove' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('ticket_type remove task')
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_remove_error_bad_type(self):
         """
         Tests the 'ticket_type remove' command in trac-admin.  This particular
         test tries to remove a ticket type that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type remove bad_type')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_order_down_ok(self):
         """
         Tests the 'ticket_type order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('ticket_type order defect down')
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_order_up_ok(self):
         """
         Tests the 'ticket_type order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('ticket_type order enhancement up')
         rv, output = self._execute('ticket_type list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_ticket_type_order_error_bad_type(self):
         """
         Tests the 'priority order' command in trac-admin.  This particular
         test tries to reorder a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('ticket_type order bad_type up')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Priority tests
 
@@ -601,33 +675,30 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_add_ok(self):
         """
         Tests the 'priority add' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('priority add new_priority')
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_add_many_ok(self):
         """
         Tests adding more than 10 priority values.  This makes sure that
         ordering is preserved when adding more than 10 values.
         """
-        test_name = sys._getframe().f_code.co_name
         for i in xrange(11):
             self._execute('priority add p%s' % i)
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_add_error_already_exists(self):
         """
@@ -635,94 +706,85 @@ class TracadminTestCase(unittest.TestCas
         test passes a priority name that already exists and checks for an
         error message.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority add blocker')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_change_ok(self):
         """
         Tests the 'priority change' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('priority change major normal')
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_change_error_bad_priority(self):
         """
         Tests the 'priority change' command in trac-admin.  This particular
         test tries to change a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority change bad_priority changed_name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_change_error_bad_new_name(self):
         """
         Tests the 'priority change' command in trac-admin.  This particular
         test tries to change a priority to a name that already exists.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority change major minor')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_remove_ok(self):
         """
         Tests the 'priority remove' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('priority remove major')
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_remove_error_bad_priority(self):
         """
         Tests the 'priority remove' command in trac-admin.  This particular
         test tries to remove a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority remove bad_priority')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_order_down_ok(self):
         """
         Tests the 'priority order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('priority order blocker down')
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_order_up_ok(self):
         """
         Tests the 'priority order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('priority order critical up')
         rv, output = self._execute('priority list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_priority_order_error_bad_priority(self):
         """
         Tests the 'priority order' command in trac-admin.  This particular
         test tries to reorder a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('priority remove bad_priority')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Severity tests
 
@@ -732,21 +794,19 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_add_ok(self):
         """
         Tests the 'severity add' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add new_severity')
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_add_error_already_exists(self):
         """
@@ -754,102 +814,93 @@ class TracadminTestCase(unittest.TestCas
         test passes a severity name that already exists and checks for an
         error message.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add blocker')
         rv, output = self._execute('severity add blocker')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_change_ok(self):
         """
         Tests the 'severity add' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add critical')
         self._execute('severity change critical "end-of-the-world"')
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_change_error_bad_severity(self):
         """
         Tests the 'severity change' command in trac-admin.  This particular
         test tries to change a severity that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('severity change bad_severity changed_name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_change_error_bad_new_name(self):
         """
         Tests the 'severity change' command in trac-admin.  This particular
         test tries to change a severity to a name that already exists.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add major')
         self._execute('severity add critical')
         rv, output = self._execute('severity change critical major')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_remove_ok(self):
         """
         Tests the 'severity add' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity remove trivial')
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_remove_error_bad_severity(self):
         """
         Tests the 'severity remove' command in trac-admin.  This particular
         test tries to remove a severity that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('severity remove bad_severity')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_order_down_ok(self):
         """
         Tests the 'severity order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add foo')
         self._execute('severity add bar')
         self._execute('severity order foo down')
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_order_up_ok(self):
         """
         Tests the 'severity order' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('severity add foo')
         self._execute('severity add bar')
         self._execute('severity order bar up')
         rv, output = self._execute('severity list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_severity_order_error_bad_severity(self):
         """
         Tests the 'severity order' command in trac-admin.  This particular
         test tries to reorder a priority that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('severity remove bad_severity')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Version tests
 
@@ -859,21 +910,19 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_add_ok(self):
         """
         Tests the 'version add' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('version add 9.9 "%s"' % self._test_date)
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_add_error_already_exists(self):
         """
@@ -881,86 +930,78 @@ class TracadminTestCase(unittest.TestCas
         test passes a version name that already exists and checks for an
         error message.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('version add 1.0 "%s"' % self._test_date)
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_rename_ok(self):
         """
         Tests the 'version rename' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('version rename 1.0 9.9')
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_rename_error_bad_version(self):
         """
         Tests the 'version rename' command in trac-admin.  This particular
         test tries to rename a version that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('version rename bad_version changed_name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_time_ok(self):
         """
         Tests the 'version time' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('version time 2.0 "%s"' % self._test_date)
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_time_unset_ok(self):
         """
         Tests the 'version time' command in trac-admin.  This particular
         test passes valid arguments for unsetting the date.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('version time 2.0 "%s"' % self._test_date)
         self._execute('version time 2.0 ""')
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_time_error_bad_version(self):
         """
         Tests the 'version time' command in trac-admin.  This particular
         test tries to change the time on a version that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('version time bad_version "%s"'
                                    % self._test_date)
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_remove_ok(self):
         """
         Tests the 'version remove' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('version remove 1.0')
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_version_remove_error_bad_version(self):
         """
         Tests the 'version remove' command in trac-admin.  This particular
         test tries to remove a version that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('version remove bad_version')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     # Milestone tests
 
@@ -970,33 +1011,30 @@ class TracadminTestCase(unittest.TestCas
         has no command arguments, it is hard to call it incorrectly.  As
         a result, there is only this one test.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_add_ok(self):
         """
         Tests the 'milestone add' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('milestone add new_milestone "%s"' % self._test_date)
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_add_utf8_ok(self):
         """
         Tests the 'milestone add' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute(u'milestone add \xa9tat_final "%s"'  #\xc2\xa9
-                              % self._test_date)
+                      % self._test_date)
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_add_error_already_exists(self):
         """
@@ -1004,78 +1042,86 @@ class TracadminTestCase(unittest.TestCas
         test passes a milestone name that already exists and checks for an
         error message.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone add milestone1 "%s"'
                                    % self._test_date)
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_milestone_add_invalid_date(self):
+        rv, output = self._execute('milestone add new_milestone <add>')
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output, {
+            'hint': self._datetime_format_hint,
+            'isohint': get_datetime_format_hint('iso8601')
+        })
 
     def test_milestone_rename_ok(self):
         """
         Tests the 'milestone rename' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('milestone rename milestone1 changed_milestone')
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_rename_error_bad_milestone(self):
         """
         Tests the 'milestone rename' command in trac-admin.  This particular
         test tries to rename a milestone that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone rename bad_milestone 
changed_name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_due_ok(self):
         """
         Tests the 'milestone due' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('milestone due milestone2 "%s"' % self._test_date)
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_due_unset_ok(self):
         """
         Tests the 'milestone due' command in trac-admin.  This particular
         test passes valid arguments for unsetting the due date.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('milestone due milestone2 "%s"' % self._test_date)
         self._execute('milestone due milestone2 ""')
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_due_error_bad_milestone(self):
         """
         Tests the 'milestone due' command in trac-admin.  This particular
         test tries to change the due date on a milestone that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone due bad_milestone "%s"'
                                    % self._test_date)
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_milestone_due_invalid_date(self):
+        rv, output = self._execute('milestone due milestone1 <due>')
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output, {
+            'hint': self._datetime_format_hint,
+            'isohint': get_datetime_format_hint('iso8601')
+        })
 
     def test_milestone_completed_ok(self):
         """
         Tests the 'milestone completed' command in trac-admin.  This particular
         test passes valid arguments and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
-
         self._execute('milestone completed milestone2 "%s"' % self._test_date)
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_completed_error_bad_milestone(self):
         """
@@ -1083,216 +1129,283 @@ class TracadminTestCase(unittest.TestCas
         test tries to change the completed date on a milestone that does not
         exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone completed bad_milestone "%s"'
                                    % self._test_date)
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
+
+    def test_milestone_completed_invalid_date(self):
+        rv, output = self._execute('milestone completed milestone1 <com>')
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output, {
+            'hint': self._datetime_format_hint,
+            'isohint': get_datetime_format_hint('iso8601')
+        })
 
     def test_milestone_remove_ok(self):
         """
         Tests the 'milestone remove' command in trac-admin.  This particular
         test passes a valid argument and checks for success.
         """
-        test_name = sys._getframe().f_code.co_name
         self._execute('milestone remove milestone3')
         rv, output = self._execute('milestone list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_milestone_remove_error_bad_milestone(self):
         """
         Tests the 'milestone remove' command in trac-admin.  This particular
         test tries to remove a milestone that does not exist.
         """
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('milestone remove bad_milestone')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
     def test_backslash_use_ok(self):
-        test_name = sys._getframe().f_code.co_name
         if self._admin.interactive:
             self._execute('version add \\')
         else:
             self._execute(r"version add '\'")
         rv, output = self._execute('version list')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_no_sessions(self):
-        test_name = sys._getframe().f_code.co_name
         rv, output = self._execute('session list authenticated')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_authenticated(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session list authenticated')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_anonymous(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session list anonymous')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_all(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         if self._admin.interactive:
             rv, output = self._execute("session list *")
         else:
             rv, output = self._execute("session list '*'")
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_authenticated_sid(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session list name00')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_anonymous_sid(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session list name10:0')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
     def test_session_list_missing_sid(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session list thisdoesntexist')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_add_missing_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_add_missing_sid(self):
         rv, output = self._execute('session add')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_add_duplicate_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_add_duplicate_sid(self):
         _prep_session_table(self.env)
         rv, output = self._execute('session add name00')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_add_sid_all(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_add_sid_all(self):
         rv, output = self._execute('session add john John j...@example.org')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list john')
-        self.assertEqual(self.expected_results[test_name]
-                         % {'today': format_date(None, console_date_format)},
-                         output)
+        self.assertExpectedResult(output, {
+            'today': format_date(None, console_date_format)
+        })
 
-    def  test_session_add_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_add_sid(self):
         rv, output = self._execute('session add john')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list john')
-        self.assertEqual(self.expected_results[test_name]
-                         % {'today': format_date(None, console_date_format)},
-                         output)
+        self.assertExpectedResult(output, {
+            'today': format_date(None, console_date_format)
+        })
 
-    def  test_session_add_sid_name(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_add_sid_name(self):
         rv, output = self._execute('session add john John')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list john')
-        self.assertEqual(self.expected_results[test_name]
-                         % {'today': format_date(None, console_date_format)},
-                         output)
+        self.assertExpectedResult(output,  {
+            'today': format_date(None, console_date_format)
+        })
 
-    def  test_session_set_attr_name(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_name(self):
         _prep_session_table(self.env)
         rv, output = self._execute('session set name name00 JOHN')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list name00')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
 
-    def  test_session_set_attr_email(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_email(self):
         _prep_session_table(self.env)
         rv, output = self._execute('session set email name00 j...@example.org')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list name00')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
 
-    def  test_session_set_attr_missing_attr(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_missing_attr(self):
         rv, output = self._execute('session set')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_set_attr_missing_value(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_missing_value(self):
         rv, output = self._execute('session set name john')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_set_attr_missing_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_missing_sid(self):
         rv, output = self._execute('session set name')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_set_attr_nonexistent_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_set_attr_nonexistent_sid(self):
         rv, output = self._execute('session set name john foo')
-        self.assertEqual(2, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_delete_sid(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_delete_sid(self):
         _prep_session_table(self.env)
         rv, output = self._execute('session delete name00')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list nam00')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
 
-    def  test_session_delete_missing_params(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_delete_missing_params(self):
         rv, output = self._execute('session delete')
-        self.assertEqual(0, rv)
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertEqual(0, rv, output)
+        self.assertExpectedResult(output)
 
-    def  test_session_delete_anonymous(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_delete_anonymous(self):
         _prep_session_table(self.env)
         rv, output = self._execute('session delete anonymous')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list *')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
 
     def test_session_delete_multiple_sids(self):
-        test_name = sys._getframe().f_code.co_name
         _prep_session_table(self.env)
         rv, output = self._execute('session delete name00 name01 name02 '
                                    'name03')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list *')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
 
-    def  test_session_purge_age(self):
-        test_name = sys._getframe().f_code.co_name
+    def test_session_purge_age(self):
         _prep_session_table(self.env, spread_visits=True)
         rv, output = self._execute('session purge 20100112')
-        self.assertEqual(0, rv)
+        self.assertEqual(0, rv, output)
         rv, output = self._execute('session list *')
-        self.assertEqual(self.expected_results[test_name], output)
+        self.assertExpectedResult(output)
+
+    def test_session_purge_invalid_date(self):
+        rv, output = self._execute('session purge <purge>')
+        self.assertEqual(2, rv, output)
+        self.assertExpectedResult(output, {
+            'hint': self._datetime_format_hint,
+            'isohint': get_datetime_format_hint('iso8601')
+        })
+
+    def test_help_milestone_due(self):
+        doc = self._get_command_help('milestone', 'due')
+        self.assertIn(self._datetime_format_hint, doc)
+        self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
+
+    def test_help_milestone_completed(self):
+        doc = self._get_command_help('milestone', 'completed')
+        self.assertIn(self._datetime_format_hint, doc)
+        self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
+
+    def test_help_version_time(self):
+        doc = self._get_command_help('version', 'time')
+        self.assertIn(self._datetime_format_hint, doc)
+        self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
+
+    def test_help_session_purge(self):
+        doc = self._get_command_help('session', 'purge')
+        self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
+
+
+class TracadminNoEnvTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self._admin = TracAdmin()
+
+    def tearDown(self):
+        self._admin = None
+
+    def _execute(self, cmd, strip_trailing_space=True, input=None):
+        return execute_cmd(self._admin, cmd,
+                           strip_trailing_space=strip_trailing_space,
+                           input=input)
+
+    def test_help(self):
+        rv, output = self._execute('help')
+        output = output.splitlines()
+        self.assertEqual('', output[-3])
+        self.assertEqual('help     Show documentation', output[-2])
+        self.assertEqual('initenv  Create and initialize a new environment',
+                         output[-1])
+
+    def test_help_with_nocmd(self):
+        rv, output = self._execute('help nocmd')
+        output = output.splitlines()
+        self.assertEqual(["No documentation found for 'nocmd'. Use 'help' to "
+                          "see the list of commands."],
+                          output)
+
+
+class TracAdminHelpMacroTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.env = EnvironmentStub(enable=['%s.UnicodeHelpCommand' %
+                                           self.__module__])
+
+    def tearDown(self):
+        self.env.reset_db()
+
+    def test_unicode_help(self):
+        unicode_help = u'Hélp text with unicöde charàcters'
+
+        class UnicodeHelpCommand(Component):
+            implements(IAdminCommandProvider)
+            def get_admin_commands(self):
+                yield ('unicode-help', '', unicode_help,
+                       None, self._cmd)
+            def _cmd(self):
+                pass
+
+        macro = TracAdminHelpMacro(self.env)
+        help = unicode(macro.expand_macro(None, None, 'unicode-help'))
+        self.assertTrue(unicode_help in help)
 
 
 def suite():
-    return unittest.makeSuite(TracadminTestCase, 'test')
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TracadminTestCase))
+    suite.addTest(unittest.makeSuite(TracadminNoEnvTestCase))
+    suite.addTest(unittest.makeSuite(TracAdminHelpMacroTestCase))
+    return suite
+
 
 if __name__ == '__main__':
-    unittest.main()
+    unittest.main(defaultTest='suite')

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/functional.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/functional.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- 
bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/functional.py 
(original)
+++ 
bloodhound/branches/trac-1.0.2-integration/trac/trac/admin/tests/functional.py 
Sat Nov 15 01:14:46 2014
@@ -1,6 +1,67 @@
-#!/usr/bin/python
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 from trac.tests.functional import *
-from trac.util.text import unicode_to_base64, unicode_from_base64
+from trac.util.text import unicode_to_base64
+
+
+class AuthorizationTestCaseSetup(FunctionalTwillTestCaseSetup):
+    def test_authorization(self, href, perms, h2_text):
+        """Check permissions required to access an administration panel. A
+        fine-grained permissions test will also be executed if ConfigObj is
+        installed.
+
+        :param href: the relative href of the administration panel
+        :param perms: list or tuple of permissions required to access
+                      the administration panel
+        :param h2_text: the body of the h2 heading on the administration
+                        panel"""
+        self._tester.go_to_front()
+        self._tester.logout()
+        self._tester.login('user')
+        if isinstance(perms, basestring):
+            perms = (perms, )
+
+        h2 = r'<h2>[ \t\n]*%s[ \t\n]*' \
+             r'( <span class="trac-count">\(\d+\)</span>)?[ \t\n]*</h2>'
+        try:
+            for perm in perms:
+                try:
+                    tc.go(href)
+                    tc.find("No administration panels available")
+                    self._testenv.grant_perm('user', perm)
+                    tc.go(href)
+                    tc.find(h2 % h2_text)
+                finally:
+                    self._testenv.revoke_perm('user', perm)
+                try:
+                    tc.go(href)
+                    tc.find("No administration panels available")
+                    self._testenv.enable_authz_permpolicy({
+                        href.strip('/').replace('/', ':', 1): {'user': perm},
+                    })
+                    tc.go(href)
+                    tc.find(h2 % h2_text)
+                except ImportError:
+                    pass
+                finally:
+                    self._testenv.disable_authz_permpolicy()
+        finally:
+            self._tester.go_to_front()
+            self._tester.logout()
+            self._tester.login('admin')
+
 
 class TestBasicSettings(FunctionalTwillTestCaseSetup):
     def runTest(self):
@@ -11,24 +72,36 @@ class TestBasicSettings(FunctionalTwillT
         tc.find('https://my.example.com/something')
 
 
+class TestBasicSettingsAuthorization(AuthorizationTestCaseSetup):
+    def runTest(self):
+        """Check permissions required to access Basic Settings panel."""
+        self.test_authorization('/admin/general/basics', 'TRAC_ADMIN',
+                                "Basic Settings")
+
+
 class TestLoggingNone(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Turn off logging."""
         # For now, we just check that it shows up.
-        self._tester.go_to_admin()
-        tc.follow('Logging')
+        self._tester.go_to_admin("Logging")
         tc.find('trac.log')
         tc.formvalue('modlog', 'log_type', 'none')
         tc.submit()
         tc.find('selected="selected">None</option')
 
 
+class TestLoggingAuthorization(AuthorizationTestCaseSetup):
+    def runTest(self):
+        """Check permissions required to access Logging panel."""
+        self.test_authorization('/admin/general/logging', 'TRAC_ADMIN',
+                                "Logging")
+
+
 class TestLoggingToFile(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Turn logging back on."""
         # For now, we just check that it shows up.
-        self._tester.go_to_admin()
-        tc.follow('Logging')
+        self._tester.go_to_admin("Logging")
         tc.find('trac.log')
         tc.formvalue('modlog', 'log_type', 'file')
         tc.formvalue('modlog', 'log_file', 'trac.log2')
@@ -43,8 +116,7 @@ class TestLoggingToFileNormal(Functional
     def runTest(self):
         """Setting logging back to normal."""
         # For now, we just check that it shows up.
-        self._tester.go_to_admin()
-        tc.follow('Logging')
+        self._tester.go_to_admin("Logging")
         tc.find('trac.log')
         tc.formvalue('modlog', 'log_file', 'trac.log')
         tc.formvalue('modlog', 'log_level', 'DEBUG')
@@ -54,11 +126,18 @@ class TestLoggingToFileNormal(Functional
         tc.find('selected="selected">DEBUG</option>')
 
 
+class TestPermissionsAuthorization(AuthorizationTestCaseSetup):
+    def runTest(self):
+        """Check permissions required to access Permissions panel."""
+        self.test_authorization('/admin/general/perm',
+                                ('PERMISSION_GRANT', 'PERMISSION_REVOKE'),
+                                "Manage Permissions and Groups")
+
+
 class TestCreatePermissionGroup(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Create a permissions group"""
-        self._tester.go_to_admin()
-        tc.follow('Permissions')
+        self._tester.go_to_admin("Permissions")
         tc.find('Manage Permissions')
         tc.formvalue('addperm', 'gp_subject', 'somegroup')
         tc.formvalue('addperm', 'action', 'REPORT_CREATE')
@@ -71,8 +150,7 @@ class TestCreatePermissionGroup(Function
 class TestAddUserToGroup(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Add a user to a permissions group"""
-        self._tester.go_to_admin()
-        tc.follow('Permissions')
+        self._tester.go_to_admin("Permissions")
         tc.find('Manage Permissions')
         tc.formvalue('addsubj', 'sg_subject', 'authenticated')
         tc.formvalue('addsubj', 'sg_group', 'somegroup')
@@ -81,12 +159,35 @@ class TestAddUserToGroup(FunctionalTwill
         somegroup = unicode_to_base64('somegroup')
         tc.find('%s:%s' % (authenticated, somegroup))
 
+        revoke_checkbox = '%s:%s' % (unicode_to_base64('anonymous'),
+                                     unicode_to_base64('PERMISSION_GRANT'))
+        tc.formvalue('addperm', 'gp_subject', 'anonymous')
+        tc.formvalue('addperm', 'action', 'PERMISSION_GRANT')
+        tc.submit()
+        tc.find(revoke_checkbox)
+        self._testenv.get_trac_environment().config.touch()
+        self._tester.logout()
+        self._tester.go_to_admin("Permissions")
+        try:
+            tc.formvalue('addsubj', 'sg_subject', 'someuser')
+            tc.formvalue('addsubj', 'sg_group', 'authenticated')
+            tc.submit()
+            tc.find("The subject someuser was not added to the "
+                    "group authenticated because the group has "
+                    "TICKET_CHGPROP permission and users cannot "
+                    "grant permissions they don't possess.")
+        finally:
+            self._tester.login('admin')
+            self._tester.go_to_admin("Permissions")
+            tc.formvalue('revokeform', 'sel', revoke_checkbox)
+            tc.submit()
+            tc.notfind(revoke_checkbox)
+
 
 class TestRemoveUserFromGroup(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Remove a user from a permissions group"""
-        self._tester.go_to_admin()
-        tc.follow('Permissions')
+        self._tester.go_to_admin("Permissions")
         tc.find('Manage Permissions')
         authenticated = unicode_to_base64('authenticated')
         somegroup = unicode_to_base64('somegroup')
@@ -99,8 +200,7 @@ class TestRemoveUserFromGroup(Functional
 class TestRemovePermissionGroup(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Remove a permissions group"""
-        self._tester.go_to_admin()
-        tc.follow('Permissions')
+        self._tester.go_to_admin("Permissions")
         tc.find('Manage Permissions')
         somegroup = unicode_to_base64('somegroup')
         REPORT_CREATE = unicode_to_base64('REPORT_CREATE')
@@ -114,25 +214,147 @@ class TestRemovePermissionGroup(Function
 class TestPluginSettings(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Check plugin settings."""
-        self._tester.go_to_admin()
-        tc.follow('Plugins')
+        self._tester.go_to_admin("Plugins")
         tc.find('Manage Plugins')
         tc.find('Install Plugin')
 
 
+class TestPluginsAuthorization(AuthorizationTestCaseSetup):
+    def runTest(self):
+        """Check permissions required to access Logging panel."""
+        self.test_authorization('/admin/general/plugin', 'TRAC_ADMIN',
+                                "Manage Plugins")
+
+
+class RegressionTestTicket10752(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """Test for regression of http://trac.edgewall.org/ticket/10752
+        Permissions on the web admin page should be greyed out when they
+        are no longer defined.
+        """
+        env = self._testenv.get_trac_environment()
+        try:
+            env.db_transaction("INSERT INTO permission VALUES (%s,%s)",
+                               ('anonymous', 'NOTDEFINED_PERMISSION'))
+        except env.db_exc.IntegrityError:
+            pass
+        env.config.touch()
+
+        self._tester.go_to_admin("Permissions")
+        tc.find('<span class="missing" '
+                'title="NOTDEFINED_PERMISSION is no longer defined">'
+                'NOTDEFINED_PERMISSION</span>')
+
+
+class RegressionTestTicket11069(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """Test for regression of http://trac.edgewall.org/ticket/11069
+        The permissions list should only be populated with permissions that
+        the user can grant."""
+        self._tester.go_to_front()
+        self._tester.logout()
+        self._tester.login('user')
+        self._testenv.grant_perm('user', 'PERMISSION_GRANT')
+        env = self._testenv.get_trac_environment()
+        from trac.perm import PermissionSystem
+        user_perms = PermissionSystem(env).get_user_permissions('user')
+        all_actions = PermissionSystem(env).get_actions()
+        try:
+            self._tester.go_to_admin("Permissions")
+            for action in all_actions:
+                option = r"<option>%s</option>" % action
+                if action in user_perms and user_perms[action] is True:
+                    tc.find(option)
+                else:
+                    tc.notfind(option)
+        finally:
+            self._testenv.revoke_perm('user', 'PERMISSION_GRANT')
+            self._tester.go_to_front()
+            self._tester.logout()
+            self._tester.login('admin')
+
+
+class RegressionTestTicket11095(FunctionalTwillTestCaseSetup):
+    """Test for regression of http://trac.edgewall.org/ticket/11095
+    The permission is truncated if it overflows the available space (CSS)
+    and the full permission name is shown in the title on hover.
+    """
+    def runTest(self):
+        self._tester.go_to_admin("Permissions")
+        tc.find('<span title="MILESTONE_VIEW">MILESTONE_VIEW</span>')
+        tc.find('<span title="WIKI_VIEW">WIKI_VIEW</span>')
+
+
+class RegressionTestTicket11117(FunctionalTwillTestCaseSetup):
+    """Test for regression of http://trac.edgewall.org/ticket/11117
+    Hint should be shown on the Basic Settings admin panel when pytz is not
+    installed.
+    """
+    def runTest(self):
+        self._tester.go_to_admin("Basic Settings")
+        pytz_hint = "Install pytz for a complete list of timezones."
+        from trac.util.datefmt import pytz
+        if pytz is None:
+            tc.find(pytz_hint)
+        else:
+            tc.notfind(pytz_hint)
+
+
+class RegressionTestTicket11257(FunctionalTwillTestCaseSetup):
+    """Test for regression of http://trac.edgewall.org/ticket/11257
+    Hints should be shown on the Basic Settings admin panel when Babel is not
+    installed.
+    """
+    def runTest(self):
+        from trac.util.translation import get_available_locales, has_babel
+
+        babel_hint_lang = "Install Babel for extended language support."
+        babel_hint_date = "Install Babel for localized date formats."
+        catalog_hint = "Message catalogs have not been compiled."
+        language_select = '<select name="default_language">'
+        disabled_language_select = \
+            '<select name="default_language" disabled="disabled" ' \
+            'title="Translations are currently unavailable">'
+
+        self._tester.go_to_admin("Basic Settings")
+        if has_babel:
+            tc.notfind(babel_hint_lang)
+            tc.notfind(babel_hint_date)
+            if get_available_locales():
+                tc.find(language_select)
+                tc.notfind(catalog_hint)
+            else:
+                tc.find(disabled_language_select)
+                tc.find(catalog_hint)
+        else:
+            tc.find(disabled_language_select)
+            tc.find(babel_hint_lang)
+            tc.find(babel_hint_date)
+            tc.notfind(catalog_hint)
+
+
 def functionalSuite(suite=None):
     if not suite:
-        import trac.tests.functional.testcases
-        suite = trac.tests.functional.testcases.functionalSuite()
+        import trac.tests.functional
+        suite = trac.tests.functional.functionalSuite()
     suite.addTest(TestBasicSettings())
+    suite.addTest(TestBasicSettingsAuthorization())
     suite.addTest(TestLoggingNone())
+    suite.addTest(TestLoggingAuthorization())
     suite.addTest(TestLoggingToFile())
     suite.addTest(TestLoggingToFileNormal())
+    suite.addTest(TestPermissionsAuthorization())
     suite.addTest(TestCreatePermissionGroup())
     suite.addTest(TestAddUserToGroup())
     suite.addTest(TestRemoveUserFromGroup())
     suite.addTest(TestRemovePermissionGroup())
     suite.addTest(TestPluginSettings())
+    suite.addTest(TestPluginsAuthorization())
+    suite.addTest(RegressionTestTicket10752())
+    suite.addTest(RegressionTestTicket11069())
+    suite.addTest(RegressionTestTicket11095())
+    suite.addTest(RegressionTestTicket11117())
+    suite.addTest(RegressionTestTicket11257())
     return suite
 
 


Reply via email to