Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/datefmt.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/datefmt.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/datefmt.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/datefmt.py 
Sat Nov 15 01:14:46 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2007-2009 Edgewall Software
+# Copyright (C) 2007-2013 Edgewall Software
 # Copyright (C) 2007 Matt Good <t...@matt-good.net>
 # All rights reserved.
 #
@@ -15,23 +15,21 @@
 # Author: Matt Good <t...@matt-good.net>
 
 import datetime
+import locale
 import os
 import time
 import unittest
 
+import trac.tests.compat
 from trac.core import TracError
-from trac.util import datefmt, translation
+from trac.util import datefmt
 
 try:
-    import pytz
-except ImportError:
-    pytz = None
-try:
     from babel import Locale
 except ImportError:
     Locale = None
 
-if pytz is None:
+if datefmt.pytz is None:
     PytzTestCase = None
 else:
     class PytzTestCase(unittest.TestCase):
@@ -99,19 +97,6 @@ else:
             dt = datefmt.to_datetime(t, tz)
             self.assertEqual(datetime.timedelta(0, 7200), dt.utcoffset())
 
-        def test_parse_date_across_dst_boundary(self):
-            tz = datefmt.get_timezone('Europe/Zurich')
-            # DST start - 31 March, 02:00
-            format = '%Y-%m-%d %H:%M:%S %Z%z'
-            expected = '2002-03-31 03:30:00 CEST+0200'
-            # iso8601
-            t = datefmt.parse_date('2002-03-31T02:30:00', tz)
-            self.assertEqual(expected, t.strftime(format))
-            # strptime
-            t = datetime.datetime(2002, 3, 31, 2, 30)
-            t = datefmt.parse_date(t.strftime('%x %X'), tz)
-            self.assertEqual(expected, t.strftime(format))
-
         def test_to_datetime_astimezone(self):
             tz = datefmt.get_timezone('Europe/Paris')
             t = datetime.datetime(2012, 3, 25, 2, 15, tzinfo=datefmt.utc)
@@ -121,11 +106,11 @@ else:
         def test_to_datetime_tz_from_naive_datetime_is_localtz(self):
             t = datetime.datetime(2012, 3, 25, 2, 15)
             dt = datefmt.to_datetime(t)
-            self.assert_(isinstance(dt.tzinfo, datefmt.LocalTimezone))
+            self.assertIsInstance(dt.tzinfo, datefmt.LocalTimezone)
 
         def test_to_datetime_tz_from_now_is_localtz(self):
             dt = datefmt.to_datetime(None)
-            self.assert_(isinstance(dt.tzinfo, datefmt.LocalTimezone))
+            self.assertIsInstance(dt.tzinfo, datefmt.LocalTimezone)
 
 
 class ParseISO8601TestCase(unittest.TestCase):
@@ -205,7 +190,7 @@ class ParseISO8601TestCase(unittest.Test
         t = datetime.datetime(2012, 10, 11, 2, 40, 57, 0, datefmt.localtz)
         dt = datefmt.parse_date('2012-10-11T02:40:57')
         self.assertEqual(t, dt)
-        self.assert_(isinstance(dt.tzinfo, datefmt.LocalTimezone))
+        self.assertIsInstance(dt.tzinfo, datefmt.LocalTimezone)
 
     def test_iso8601_naive_tz_used_tzinfo_arg(self):
         tz = datefmt.timezone('GMT +1:00')
@@ -221,7 +206,7 @@ class ParseISO8601TestCase(unittest.Test
         self.assertEqual(datetime.timedelta(hours=-9, minutes=-30),
                          dt.utcoffset())
 
-    if pytz:
+    if datefmt.pytz:
         def test_iso8601_naive_tz_normalize_non_existent_time(self):
             t = datetime.datetime(2012, 3, 25, 1, 15, 57, 0, datefmt.utc)
             tz = datefmt.timezone('Europe/Paris')
@@ -238,6 +223,128 @@ class ParseISO8601TestCase(unittest.Test
             self.assertEqual(2, dt.hour)
             self.assertEqual(datetime.timedelta(hours=1), dt.utcoffset())
 
+    def test_hint_iso8601(self):
+        def validate(locale=None):
+            try:
+                datefmt.parse_date('2001-0a-01', locale=locale, hint='iso8601')
+                raise self.failureException('TracError not raised')
+            except TracError, e:
+                self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', unicode(e))
+
+        validate(locale=None)
+        validate(locale='iso8601')
+        if Locale:
+            validate(locale=Locale.parse('en_US'))
+
+
+class ParseDateWithoutBabelTestCase(unittest.TestCase):
+
+    if os.name != 'nt':
+        locales = {}
+    else:
+        # LCID: http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx
+        # NLS: http://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
+        ref_time = time.gmtime(123456)
+        locales = {
+            'en_US.UTF8': ('English_United States', '1/2/1970 10:17:36 AM'),
+            'en_GB.UTF8': ('English_United Kingdom', '02/01/1970 10:17:36'),
+            'fr_FR.UTF8': ('French_France', '02/01/1970 10:17:36'),
+            'ja_JP.UTF8': ('Japanese_Japan', '1970/01/02 10:17:36'),
+            'zh_CN.UTF8': ("Chinese_People's Republic of China",
+                           '1970/1/2 10:17:36')
+        }
+
+    def setUp(self):
+        rv = locale.getlocale(locale.LC_TIME)
+        self._orig_locale = rv if rv[0] else 'C'
+
+    def tearDown(self):
+        locale.setlocale(locale.LC_ALL, self._orig_locale)
+
+    def _setlocale(self, id):
+        try:
+            mapped, ref_strftime = self.locales.get(id, (id, None))
+            locale.setlocale(locale.LC_ALL, mapped)
+            return (ref_strftime is None or
+                    ref_strftime == time.strftime('%x %X', self.ref_time))
+        except locale.Error:
+            return False
+
+    def test_parse_date_libc(self):
+        tz = datefmt.timezone('GMT +2:00')
+        expected = datetime.datetime(2010, 8, 28, 13, 45, 56, 0, tz)
+        expected_minute = datetime.datetime(2010, 8, 28, 13, 45, 0, 0, tz)
+        expected_date = datetime.datetime(2010, 8, 28, 0, 0, 0, 0, tz)
+
+        self.assertTrue(self._setlocale('C'))
+        self.assertEqual(expected,
+                         datefmt.parse_date('08/28/10 13:45:56', tz))
+        self.assertEqual(expected_minute,
+                         datefmt.parse_date('08/28/10 13:45', tz))
+        self.assertEqual(expected_date, datefmt.parse_date('08/28/10', tz))
+        self.assertEqual(expected_minute,
+                         datefmt.parse_date('28 Aug 2010 1:45 pm', tz))
+
+        if self._setlocale('en_US.UTF8'):
+            self.assertEqual(expected,
+                             datefmt.parse_date('Aug 28, 2010 1:45:56 PM', tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date('8 28, 2010 1:45:56 PM', tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date('28 Aug 2010 1:45:56 PM', tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date('28 Aug 2010 PM 1:45:56', tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date('28 Aug 2010 13:45:56', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('28 Aug 2010 PM 1:45', tz))
+            self.assertEqual(expected_date,
+                             datefmt.parse_date('28 Aug 2010', tz))
+
+        if self._setlocale('en_GB.UTF8'):
+            self.assertEqual(expected,
+                             datefmt.parse_date('28 Aug 2010 13:45:56', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('28 Aug 2010 PM 1:45', tz))
+            self.assertEqual(expected_date,
+                             datefmt.parse_date('28 Aug 2010', tz))
+
+        if self._setlocale('fr_FR.UTF8'):
+            self.assertEqual(expected,
+                             datefmt.parse_date(u'28 août 2010 13:45:56', tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date(u'août 28 2010 13:45:56', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date(u'août 28 2010 13:45', tz))
+            self.assertEqual(expected_date,
+                             datefmt.parse_date(u'août 28 2010', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('Aug 28 2010 1:45 pm', tz))
+
+        if self._setlocale('ja_JP.UTF8'):
+            self.assertEqual(expected,
+                             datefmt.parse_date('2010/08/28 13:45:56', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('2010/08/28 13:45', tz))
+            self.assertEqual(expected_date,
+                             datefmt.parse_date('2010/08/28', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('2010/Aug/28 1:45 pm', tz))
+
+        if self._setlocale('zh_CN.UTF8'):
+            self.assertEqual(expected,
+                             datefmt.parse_date(u'2010-8-28 下午01:45:56', 
tz))
+            self.assertEqual(expected,
+                             datefmt.parse_date(u'2010-8-28 01:45:56下午', 
tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date(u'2010-8-28 下午01:45', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date(u'2010-8-28 01:45下午', tz))
+            self.assertEqual(expected_date,
+                             datefmt.parse_date('2010-8-28', tz))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('2010-Aug-28 01:45 pm', tz))
+
 
 class ParseRelativeDateTestCase(unittest.TestCase):
 
@@ -417,7 +524,7 @@ class ParseRelativeDateTestCase(unittest
         self.assertEqual(datetime.datetime(2012, 3, 25, 3, 14, 59, tzinfo=tz),
                          datefmt._parse_relative_time('last second', tz, now))
 
-    if pytz:
+    if datefmt.pytz:
         def test_time_interval_across_dst(self):
             tz = datefmt.timezone('Europe/Paris')
             now = datefmt.to_datetime(datetime.datetime(2012, 3, 25, 3, 0, 41),
@@ -458,9 +565,9 @@ class ParseDateValidRangeTestCase(unitte
         datefmt.parse_date('2038-01-19T03:14:07Z')
         try:
             datefmt.parse_date('9999-12-31T23:59:59-12:00')
-            raise AssertionError('TracError not raised')
+            raise self.failureException('TracError not raised')
         except TracError, e:
-            self.assert_('is outside valid range' in unicode(e))
+            self.assertIn('is outside valid range', unicode(e))
 
     def test_min_timestamp(self):
         if os.name != 'nt':
@@ -472,9 +579,9 @@ class ParseDateValidRangeTestCase(unitte
             datefmt.parse_date('1970-01-01T00:00:00Z')
         try:
             datefmt.parse_date('0001-01-01T00:00:00+14:00')
-            raise AssertionError('TracError not raised')
+            raise self.failureException('TracError not raised')
         except TracError, e:
-            self.assert_('is outside valid range' in unicode(e))
+            self.assertIn('is outside valid range', unicode(e))
 
 
 class DateFormatTestCase(unittest.TestCase):
@@ -523,6 +630,10 @@ class DateFormatTestCase(unittest.TestCa
         self.assertEqual(datefmt.to_datetime(23L, tz), expected)
         self.assertEqual(datefmt.to_datetime(23.0, tz), expected)
 
+    def test_to_datetime_typeerror(self):
+        self.assertRaises(TypeError, datefmt.to_datetime, 'blah')
+        self.assertRaises(TypeError, datefmt.to_datetime, u'bl\xe1h')
+
     def test_format_datetime_utc(self):
         t = datetime.datetime(1970, 1, 1, 1, 0, 23, 0, datefmt.utc)
         expected = '1970-01-01T01:00:23Z'
@@ -559,6 +670,21 @@ class DateFormatTestCase(unittest.TestCa
         self.assertEqual(datefmt.format_time(t, 'iso8601', gmt01),
                          expected.split('T')[1])
 
+    def test_format_iso8601_before_1900(self):
+        t = datetime.datetime(1899, 12, 30, 23, 58, 59, 123456, datefmt.utc)
+        self.assertEqual('1899-12-30T23:58:59Z',
+                         datefmt.format_datetime(t, 'iso8601', datefmt.utc))
+        self.assertEqual('1899-12-30',
+                         datefmt.format_datetime(t, 'iso8601date',
+                                                 datefmt.utc))
+        self.assertEqual('1899-12-30',
+                         datefmt.format_date(t, 'iso8601', datefmt.utc))
+        self.assertEqual('23:58:59Z',
+                         datefmt.format_datetime(t, 'iso8601time',
+                                                 datefmt.utc))
+        self.assertEqual('23:58:59Z',
+                         datefmt.format_time(t, 'iso8601', datefmt.utc))
+
     def test_format_date_accepts_date_instances(self):
         a_date = datetime.date(2009, 8, 20)
         self.assertEqual('2009-08-20',
@@ -660,38 +786,68 @@ class ISO8601TestCase(unittest.TestCase)
                          datefmt.format_time(t, 'medium', tz, 'iso8601'))
         self.assertEqual('2010-08-28T11:45:56',
                          datefmt.format_datetime(t, 'medium', tz, 'iso8601'))
-        for f in ('long', 'full'):
-            self.assertEqual('11:45:56+02:00',
-                             datefmt.format_time(t, f, tz, 'iso8601'))
-            self.assertEqual('2010-08-28T11:45:56+02:00',
-                             datefmt.format_datetime(t, f, tz, 'iso8601'))
+        self.assertEqual('11:45:56+02:00',
+                         datefmt.format_time(t, 'long', tz, 'iso8601'))
+        self.assertEqual('2010-08-28T11:45:56+02:00',
+                         datefmt.format_datetime(t, 'long', tz, 'iso8601'))
+        self.assertEqual('11:45:56.123456+02:00',
+                         datefmt.format_time(t, 'full', tz, 'iso8601'))
+        self.assertEqual('2010-08-28T11:45:56.123456+02:00',
+                         datefmt.format_datetime(t, 'full', tz, 'iso8601'))
+
+    def test_with_babel_format_before_1900(self):
+        tz = datefmt.timezone('GMT +2:00')
+        t = datetime.datetime(1899, 8, 28, 11, 45, 56, 123456, tz)
+        for f in ('short', 'medium', 'long', 'full'):
+            self.assertEqual('1899-08-28',
+                             datefmt.format_date(t, f, tz, 'iso8601'))
+        self.assertEqual('11:45',
+                         datefmt.format_time(t, 'short', tz, 'iso8601'))
+        self.assertEqual('1899-08-28T11:45',
+                         datefmt.format_datetime(t, 'short', tz, 'iso8601'))
+        self.assertEqual('11:45:56',
+                         datefmt.format_time(t, 'medium', tz, 'iso8601'))
+        self.assertEqual('1899-08-28T11:45:56',
+                         datefmt.format_datetime(t, 'medium', tz, 'iso8601'))
+        self.assertEqual('11:45:56+02:00',
+                         datefmt.format_time(t, 'long', tz, 'iso8601'))
+        self.assertEqual('1899-08-28T11:45:56+02:00',
+                         datefmt.format_datetime(t, 'long', tz, 'iso8601'))
+        self.assertEqual('11:45:56.123456+02:00',
+                         datefmt.format_time(t, 'full', tz, 'iso8601'))
+        self.assertEqual('1899-08-28T11:45:56.123456+02:00',
+                         datefmt.format_datetime(t, 'full', tz, 'iso8601'))
 
     def test_hint(self):
         try:
             datefmt.parse_date('***', locale='iso8601', hint='date')
+            raise self.failureException('TracError not raised')
         except TracError, e:
-            self.assert_('"YYYY-MM-DD"' in unicode(e))
+            self.assertIn('"YYYY-MM-DD"', unicode(e))
         try:
             datefmt.parse_date('***', locale='iso8601', hint='datetime')
+            raise self.failureException('TracError not raised')
         except TracError, e:
-            self.assert_(u'"YYYY-MM-DDThh:mm:ss±hh:mm"' in unicode(e))
+            self.assertIn(u'"YYYY-MM-DDThh:mm:ss±hh:mm"', unicode(e))
         try:
             datefmt.parse_date('***', locale='iso8601', hint='foobar')
+            raise self.failureException('TracError not raised')
         except TracError, e:
-            self.assert_('"foobar"' in unicode(e))
+            self.assertIn('"foobar"', unicode(e))
 
 
 if Locale is None:
     I18nDateFormatTestCase = None
 else:
     class I18nDateFormatTestCase(unittest.TestCase):
+
         def test_i18n_format_datetime(self):
             tz = datefmt.timezone('GMT +2:00')
             t = datetime.datetime(2010, 8, 28, 11, 45, 56, 123456, datefmt.utc)
             en_US = Locale.parse('en_US')
-            self.assertEqual('Aug 28, 2010 1:45:56 PM',
-                             datefmt.format_datetime(t, tzinfo=tz,
-                                                     locale=en_US))
+            self.assertIn(datefmt.format_datetime(t, tzinfo=tz, locale=en_US),
+                          ('Aug 28, 2010 1:45:56 PM',
+                           'Aug 28, 2010, 1:45:56 PM'))  # CLDR 23
             en_GB = Locale.parse('en_GB')
             self.assertEqual('28 Aug 2010 13:45:56',
                              datefmt.format_datetime(t, tzinfo=tz,
@@ -706,9 +862,9 @@ else:
             self.assertEqual(u'13:45:56 28-08-2010',
                              datefmt.format_datetime(t, tzinfo=tz, locale=vi))
             zh_CN = Locale.parse('zh_CN')
-            self.assertEqual(u'2010-8-28 下午01:45:56',
-                             datefmt.format_datetime(t, tzinfo=tz,
-                                                     locale=zh_CN))
+            self.assertIn(datefmt.format_datetime(t, tzinfo=tz, locale=zh_CN),
+                          (u'2010-8-28 下午01:45:56',
+                           u'2010年8月28日 下午1:45:56'))
 
         def test_i18n_format_date(self):
             tz = datefmt.timezone('GMT +2:00')
@@ -729,8 +885,8 @@ else:
             self.assertEqual(u'07-08-2010',
                              datefmt.format_date(t, tzinfo=tz, locale=vi))
             zh_CN = Locale.parse('zh_CN')
-            self.assertEqual(u'2010-8-7',
-                             datefmt.format_date(t, tzinfo=tz, locale=zh_CN))
+            self.assertIn(datefmt.format_date(t, tzinfo=tz, locale=zh_CN),
+                          (u'2010-8-7', u'2010年8月7日'))
 
         def test_i18n_format_time(self):
             tz = datefmt.timezone('GMT +2:00')
@@ -752,8 +908,8 @@ else:
                              datefmt.format_time(t, tzinfo=tz, locale=ja))
             self.assertEqual('13:45:56',
                              datefmt.format_time(t, tzinfo=tz, locale=vi))
-            self.assertEqual(u'下午01:45:56',
-                             datefmt.format_time(t, tzinfo=tz, locale=zh_CN))
+            self.assertIn(datefmt.format_time(t, tzinfo=tz, locale=zh_CN),
+                          (u'下午01:45:56', u'下午1:45:56'))
 
         def test_i18n_datetime_hint(self):
             en_US = Locale.parse('en_US')
@@ -763,18 +919,19 @@ else:
             vi = Locale.parse('vi')
             zh_CN = Locale.parse('zh_CN')
 
-            self.assert_(datefmt.get_datetime_format_hint(en_US)
-                         in ('MMM d, yyyy h:mm:ss a', 'MMM d, y h:mm:ss a'))
-            self.assert_(datefmt.get_datetime_format_hint(en_GB)
-                         in ('d MMM yyyy HH:mm:ss', 'd MMM y HH:mm:ss'))
-            self.assert_(datefmt.get_datetime_format_hint(fr)
-                         in ('d MMM yyyy HH:mm:ss', 'd MMM y HH:mm:ss'))
-            self.assertEqual('yyyy/MM/dd H:mm:ss',
-                             datefmt.get_datetime_format_hint(ja))
-            self.assertEqual('HH:mm:ss dd-MM-yyyy',
-                             datefmt.get_datetime_format_hint(vi))
-            self.assertEqual('yyyy-M-d ahh:mm:ss',
-                             datefmt.get_datetime_format_hint(zh_CN))
+            self.assertIn(datefmt.get_datetime_format_hint(en_US),
+                          ('MMM d, yyyy h:mm:ss a', 'MMM d, y h:mm:ss a',
+                           'MMM d, y, h:mm:ss a'))
+            self.assertIn(datefmt.get_datetime_format_hint(en_GB),
+                          ('d MMM yyyy HH:mm:ss', 'd MMM y HH:mm:ss'))
+            self.assertIn(datefmt.get_datetime_format_hint(fr),
+                          ('d MMM yyyy HH:mm:ss', 'd MMM y HH:mm:ss'))
+            self.assertIn(datefmt.get_datetime_format_hint(ja),
+                          ('yyyy/MM/dd H:mm:ss', 'y/MM/dd H:mm:ss'))
+            self.assertIn(datefmt.get_datetime_format_hint(vi),
+                          ('HH:mm:ss dd-MM-yyyy', 'HH:mm:ss dd-MM-y'))
+            self.assertIn(datefmt.get_datetime_format_hint(zh_CN),
+                          ('yyyy-M-d ahh:mm:ss', u'y年M月d日 ah:mm:ss'))
 
         def test_i18n_date_hint(self):
             en_US = Locale.parse('en_US')
@@ -784,18 +941,18 @@ else:
             vi = Locale.parse('vi')
             zh_CN = Locale.parse('zh_CN')
 
-            self.assert_(datefmt.get_date_format_hint(en_US)
-                         in ('MMM d, yyyy', 'MMM d, y'))
-            self.assert_(datefmt.get_date_format_hint(en_GB)
-                         in ('d MMM yyyy', 'd MMM y'))
-            self.assert_(datefmt.get_date_format_hint(fr)
-                         in ('d MMM yyyy', 'd MMM y'))
-            self.assertEqual('yyyy/MM/dd',
-                             datefmt.get_date_format_hint(ja))
-            self.assertEqual('dd-MM-yyyy',
-                             datefmt.get_date_format_hint(vi))
-            self.assertEqual('yyyy-M-d',
-                             datefmt.get_date_format_hint(zh_CN))
+            self.assertIn(datefmt.get_date_format_hint(en_US),
+                          ('MMM d, yyyy', 'MMM d, y'))
+            self.assertIn(datefmt.get_date_format_hint(en_GB),
+                          ('d MMM yyyy', 'd MMM y'))
+            self.assertIn(datefmt.get_date_format_hint(fr),
+                          ('d MMM yyyy', 'd MMM y'))
+            self.assertIn(datefmt.get_date_format_hint(ja),
+                          ('yyyy/MM/dd', 'y/MM/dd'))
+            self.assertIn(datefmt.get_date_format_hint(vi),
+                          ('dd-MM-yyyy', 'dd-MM-y'))
+            self.assertIn(datefmt.get_date_format_hint(zh_CN),
+                          ('yyyy-M-d', u'y年M月d日'))
 
         def test_i18n_parse_date_iso8609(self):
             tz = datefmt.timezone('GMT +2:00')
@@ -864,16 +1021,22 @@ else:
             self.assertEqual(expected_minute,
                              datefmt.parse_date(u'août 28 2010 13:45', tz,
                                                 fr))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('Aug 28 2010 1:45 PM', tz, fr))
 
             self.assertEqual(expected,
                              datefmt.parse_date('2010/08/28 13:45:56', tz, ja))
             self.assertEqual(expected_minute,
                              datefmt.parse_date('2010/08/28 13:45', tz, ja))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('2010/Aug/28 1:45 PM', tz, ja))
 
             self.assertEqual(expected,
                              datefmt.parse_date('13:45:56 28-08-2010', tz, vi))
             self.assertEqual(expected_minute,
                              datefmt.parse_date('13:45 28-08-2010', tz, vi))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('1:45PM 28-Aug-2010', tz, vi))
 
             self.assertEqual(expected,
                              datefmt.parse_date(u'2010-8-28 下午01:45:56',
@@ -887,6 +1050,9 @@ else:
             self.assertEqual(expected_minute,
                              datefmt.parse_date(u'2010-8-28 01:45下午', tz,
                                                 zh_CN))
+            self.assertEqual(expected_minute,
+                             datefmt.parse_date('2010-Aug-28 01:45PM', tz,
+                                                zh_CN))
 
         def test_i18n_parse_date_datetime_meridiem(self):
             tz = datefmt.timezone('GMT +2:00')
@@ -945,20 +1111,27 @@ else:
                              datefmt.parse_date(u'2010-8-28', tz, zh_CN))
 
         def test_i18n_parse_date_roundtrip(self):
+            from pkg_resources import resource_listdir
+            locales = sorted(dirname
+                             for dirname in resource_listdir('trac', 'locale')
+                             if '.' not in dirname)
+
             tz = datefmt.timezone('GMT +2:00')
             t = datetime.datetime(2010, 8, 28, 11, 45, 56, 123456, datefmt.utc)
-            expected = datetime.datetime(2010, 8, 28, 13, 45, 56, 0, tz)
+            tz_t = datetime.datetime(2010, 8, 28, 13, 45, 56, 0, tz)
 
-            for locale in translation.get_available_locales():
+            for locale in locales:
                 locale = Locale.parse(locale)
                 formatted = datefmt.format_datetime(t, tzinfo=tz,
                                                     locale=locale)
 
                 actual = datefmt.parse_date(formatted, tz, locale)
-                self.assertEqual(expected, actual,
-                                 '%r != %r (%r)' % (expected, actual, locale))
+                self.assertEqual(tz_t, actual,
+                                 '%r != %r (%r %r)' % (tz_t, actual, formatted,
+                                                       locale))
+                self.assertEqual(tz_t.isoformat(), actual.isoformat())
 
-                actual = datefmt.format_datetime(expected, tzinfo=tz,
+                actual = datefmt.format_datetime(tz_t, tzinfo=tz,
                                                  locale=locale)
                 self.assertEqual(formatted, actual,
                                  '%r != %r (%r)' % (formatted, actual, locale))
@@ -966,12 +1139,12 @@ else:
         def test_format_compatibility(self):
             tz = datefmt.timezone('GMT +2:00')
             t = datetime.datetime(2010, 8, 28, 11, 45, 56, 123456, datefmt.utc)
-            tz_t = datetime.datetime(2010, 8, 28, 13, 45, 56, 123456, tz)
             en_US = Locale.parse('en_US')
 
             # Converting default format to babel's format
-            self.assertEqual('Aug 28, 2010 1:45:56 PM',
-                             datefmt.format_datetime(t, '%x %X', tz, en_US))
+            self.assertIn(datefmt.format_datetime(t, '%x %X', tz, en_US),
+                          ('Aug 28, 2010 1:45:56 PM',
+                           'Aug 28, 2010, 1:45:56 PM'))  # CLDR 23
             self.assertEqual('Aug 28, 2010',
                              datefmt.format_datetime(t, '%x', tz, en_US))
             self.assertEqual('1:45:56 PM',
@@ -1162,6 +1335,29 @@ class LocalTimezoneTestCase(unittest.Tes
         self.assertEqual('2011-10-30T02:45:42.123456+01:00',
                          dt.astimezone(datefmt.localtz).isoformat())
 
+    def test_astimezone_invalid_range_on_gmt01(self):
+        self._tzset('GMT-1')
+
+        # 1899-12-30T23:59:58+00:00 is -0x83ac4e92 for time_t, out of range
+        # for 32-bit signed integer
+        dt = datetime.datetime(1899, 12, 30, 23, 59, 58, 123456, datefmt.utc)
+        self.assertEqual('1899-12-31T00:59:58.123456+01:00',
+                         dt.astimezone(datefmt.localtz).isoformat())
+        dt = datetime.datetime(1899, 12, 30, 23, 59, 58, 123456,
+                               datefmt.localtz)
+        self.assertEqual('1899-12-30T22:59:58.123456+00:00',
+                         dt.astimezone(datefmt.utc).isoformat())
+
+        # 2040-12-31T23:59:58+00:00 is 0x858c84ee for time_t, out of range for
+        # 32-bit signed integer
+        dt = datetime.datetime(2040, 12, 31, 23, 59, 58, 123456, datefmt.utc)
+        self.assertEqual('2041-01-01T00:59:58.123456+01:00',
+                         dt.astimezone(datefmt.localtz).isoformat())
+        dt = datetime.datetime(2040, 12, 31, 23, 59, 58, 123456,
+                               datefmt.localtz)
+        self.assertEqual('2040-12-31T22:59:58.123456+00:00',
+                         dt.astimezone(datefmt.utc).isoformat())
+
     def test_arithmetic_localized_non_existent_time(self):
         self._tzset('Europe/Paris')
         t = datetime.datetime(2012, 3, 25, 1, 15, 42, 123456)
@@ -1231,7 +1427,6 @@ class LocalTimezoneTestCase(unittest.Tes
     def test_arithmetic_not_localized_normalized_non_existent_time(self):
         self._tzset('Europe/Paris')
         t = datetime.datetime(2012, 3, 25, 1, 15, 42, 123456, datefmt.localtz)
-        t_utc = t.replace(tzinfo=datefmt.utc)
         t1 = t
         self.assertEqual('2012-03-25T01:15:42.123456+01:00', t1.isoformat())
         t2 = datefmt.localtz.normalize(t1 + datetime.timedelta(hours=1))
@@ -1245,7 +1440,6 @@ class LocalTimezoneTestCase(unittest.Tes
     def test_arithmetic_not_localized_normalized_ambiguous_time(self):
         self._tzset('Europe/Paris')
         t = datetime.datetime(2011, 10, 30, 1, 45, 42, 123456, datefmt.localtz)
-        t_utc = t.replace(tzinfo=datefmt.utc)
         t1 = t
         self.assertEqual('2011-10-30T01:45:42.123456+02:00', t1.isoformat())
         t2 = datefmt.localtz.normalize(t1 + datetime.timedelta(hours=1))
@@ -1259,6 +1453,235 @@ class LocalTimezoneTestCase(unittest.Tes
         self.assertEqual(datetime.timedelta(hours=1), t3 - t2)
         self.assertEqual(datetime.timedelta(hours=1), t4 - t3)
 
+    def test_london_between_1968_and_1971(self):
+        self._tzset('Europe/London')
+        # -1:00 (DST end) at 1967-10-29 03:00
+        ts = datefmt.to_timestamp(datetime.datetime(1967, 10, 30,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1967-10-30T00:00:00+00:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # +1:00 (DST start) at 1968-02-18 02:00
+        ts = datefmt.to_timestamp(datetime.datetime(1968, 2, 19,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1968-02-19T01:00:00+01:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # No DST between 1968-02-18 02:00 and 1971-10-31 03:00
+        ts = datefmt.to_timestamp(datetime.datetime(1970, 1, 1, 0, 0, 23,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1970-01-01T01:00:23+01:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # -1:00 (TZ change) at 1971-10-31 03:00
+        t = datefmt.to_datetime(datetime.datetime(1971, 10, 31, 1, 30),
+                                datefmt.localtz)
+        delta = datetime.timedelta(hours=1)
+        self.assertEqual('1971-10-31T01:30:00+01:00', t.isoformat())
+        t = datefmt.to_datetime(t + delta, datefmt.localtz)
+        self.assertEqual('1971-10-31T02:30:00+01:00', t.isoformat())
+        t = datefmt.to_datetime(t + delta, datefmt.localtz)
+        self.assertEqual('1971-10-31T02:30:00+00:00', t.isoformat())
+        t = datefmt.to_datetime(t + delta, datefmt.localtz)
+        self.assertEqual('1971-10-31T03:30:00+00:00', t.isoformat())
+
+        ts = datefmt.to_timestamp(datetime.datetime(1971, 11, 1,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1971-11-01T00:00:00+00:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+
+    def test_guatemala_dst_in_2006(self):
+        self._tzset('America/Guatemala')
+        # No DST before 2006-04-30 00:00
+        ts = datefmt.to_timestamp(datetime.datetime(2006, 4, 29,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('2006-04-28T18:00:00-06:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # +1:00 (DST start) at 2006-04-30 00:00
+        ts = datefmt.to_timestamp(datetime.datetime(2006, 8, 1,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('2006-07-31T19:00:00-05:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # -1:00 (DST end) at 2006-10-01 00:00
+        ts = datefmt.to_timestamp(datetime.datetime(2006, 10, 2,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('2006-10-01T18:00:00-06:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # No DST after 2006-10-01 00:00
+
+    def test_venezuela_in_2007(self):
+        self._tzset('America/Caracas')
+        ts = datefmt.to_timestamp(datetime.datetime(2007, 12, 8,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('2007-12-07T20:00:00-04:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # -0:30 (TZ change) at 2007-12-09 03:00
+        ts = datefmt.to_timestamp(datetime.datetime(2007, 12, 10,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('2007-12-09T19:30:00-04:30',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+
+    def test_lord_howe_island_in_198x(self):
+        self._tzset('Australia/Lord_Howe')
+        ts = datefmt.to_timestamp(datetime.datetime(1985, 3, 1,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1985-03-01T11:30:00+11:30',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        # -1:00 (DST end) at 1985-03-03 02:00
+        ts = datefmt.to_timestamp(datetime.datetime(1985, 8, 1,
+                                                    tzinfo=datefmt.utc))
+        self.assertEqual('1985-08-01T10:30:00+10:30',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+        ts = datefmt.to_timestamp(datetime.datetime(1985, 11, 1,
+                                                    tzinfo=datefmt.utc))
+        # +0:30 (DST start) at 1985-10-27 02:00
+        self.assertEqual('1985-11-01T11:00:00+11:00',
+                         datefmt.to_datetime(ts, datefmt.localtz).isoformat())
+
+    def _compare_pytz_arithmetic(self, tz, dt_naive):
+        """Compare arithmetic timezone-aware datetime between localtz and
+        pytz's timezone"""
+        localtz = datefmt.localtz
+        delta = datetime.timedelta(minutes=20)
+        n = datetime.timedelta(hours=3).seconds / delta.seconds
+        # create timezone-aware datetime instances
+        dt_localtz = datefmt.to_datetime(dt_naive - delta * n, localtz)
+        dt_tz = datefmt.to_datetime(dt_naive - delta * n, tz)
+        # compare datetime instances between -3 hours and +3 hours
+        for i in xrange(n * 2 + 1):
+            self.assertEqual(dt_tz, dt_localtz)
+            self.assertEqual(dt_tz.isoformat(), dt_localtz.isoformat())
+            dt_localtz = datefmt.to_datetime(dt_localtz + delta, localtz)
+            dt_tz = datefmt.to_datetime(dt_tz + delta, tz)
+
+    def _compare_pytz_localize_and_normalize(self, tz, dt_naive):
+        """Compare localize() and normalize() of LocalTimezone and pytz's
+        timezone"""
+        localtz = datefmt.localtz
+        delta = datetime.timedelta(minutes=20)
+        n = datetime.timedelta(hours=3).seconds / delta.seconds
+        dt_naive -= delta * n
+        # compare localize and normalize with naive datetime
+        # between -3 hours and +3 hours
+        for i in xrange(n * 2 + 1):
+            dt_localtz = localtz.localize(dt_naive)
+            dt_tz = tz.localize(dt_naive)
+            self.assertEqual(dt_tz, dt_localtz,
+                             '%r != %r (%r)' % (dt_tz, dt_localtz, dt_naive))
+            self.assertEqual(dt_tz.isoformat(), dt_localtz.isoformat(),
+                             '%r != %r (%r)' % (dt_tz.isoformat(),
+                                                dt_localtz.isoformat(),
+                                                dt_naive))
+            dt_localtz = localtz.normalize(localtz.localize(dt_naive))
+            dt_tz = tz.normalize(tz.localize(dt_naive))
+            self.assertEqual(dt_tz, dt_localtz,
+                             '%r != %r (%r)' % (dt_tz, dt_localtz, dt_naive))
+            self.assertEqual(dt_tz.isoformat(), dt_localtz.isoformat(),
+                             '%r != %r (%r)' % (dt_tz.isoformat(),
+                                                dt_localtz.isoformat(),
+                                                dt_naive))
+            dt_naive += delta
+
+    def _compare_pytz(self, tz, value, localize=True):
+        if isinstance(value, basestring):
+            value = datefmt.parse_date(value + 'Z', datefmt.utc)
+        dt_naive = value.replace(tzinfo=None)
+        self._compare_pytz_arithmetic(tz, dt_naive)
+        # `localize()` differs one of pytz's timezone when backward timezone
+        # change
+        if localize:
+            self._compare_pytz_localize_and_normalize(tz, dt_naive)
+
+    if datefmt.pytz:
+        def test_pytz_choibalsan(self):
+            tz = datefmt.timezone('Asia/Choibalsan')
+            self._tzset('Asia/Choibalsan')
+            self._compare_pytz(tz, '1977-01-01T00:00')  # No DST
+            self._compare_pytz(tz, '1978-01-01T01:00')  # +1:00 (TZ change)
+            self._compare_pytz(tz, '1978-01-01T02:00')  #       (TZ change)
+            self._compare_pytz(tz, '1982-04-01T00:00')  # No DST
+            self._compare_pytz(tz, '1983-04-01T00:00')  # +2:00 (TZ change)
+            self._compare_pytz(tz, '1983-04-01T02:00')  #       (TZ change)
+            self._compare_pytz(tz, '1983-10-01T00:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2006-03-25T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '2006-09-30T02:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2007-07-01T00:00')  # No DST in 2007
+            self._compare_pytz(tz, '2008-03-30T23:00',  #       (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '2008-03-31T00:00',  # -1:00 (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '2009-07-01T00:00')  # No DST
+
+        def test_pytz_guatemala(self):
+            tz = datefmt.timezone('America/Guatemala')
+            self._tzset('America/Guatemala')
+            self._compare_pytz(tz, '2005-07-01T00:00')  # No DST
+            self._compare_pytz(tz, '2006-04-30T00:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '2006-10-01T00:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2007-07-01T00:00')  # No DST
+
+        def test_pytz_london(self):
+            tz = datefmt.timezone('Europe/London')
+            self._tzset('Europe/London')
+            self._compare_pytz(tz, '1968-02-18T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1971-10-31T02:00',  #       (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '1971-10-31T03:00',  # -1:00 (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '1972-03-19T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1972-10-29T03:00')  # -1:00 (DST end)
+
+        def test_pytz_lord_howe_island(self):
+            tz = datefmt.timezone('Australia/Lord_Howe')
+            self._tzset('Australia/Lord_Howe')
+            self._compare_pytz(tz, '1980-07-01T00:00')  # No DST
+            self._compare_pytz(tz, '1981-03-01T00:00')  # +0:30 (TZ change)
+            self._compare_pytz(tz, '1981-03-01T00:30')  #       (TZ change)
+            self._compare_pytz(tz, '1981-10-25T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1985-03-03T02:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '1985-10-27T02:00')  # +0:30 (DST start)
+            self._compare_pytz(tz, '1986-03-16T02:00')  # -0:30 (DST end)
+
+        def test_pytz_moscow(self):
+            tz = datefmt.timezone('Europe/Moscow')
+            self._tzset('Europe/Moscow')
+            self._compare_pytz(tz, '1991-09-29T03:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '1992-01-19T02:00')  # +1:00 (TZ change)
+            self._compare_pytz(tz, '1992-01-19T03:00')  #       (TZ change)
+            self._compare_pytz(tz, '1992-03-28T23:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1992-09-26T23:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2010-03-28T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '2010-10-31T03:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2011-03-27T02:00')  # +1:00 (TZ change)
+            self._compare_pytz(tz, '2011-03-27T03:00')  #       (TZ change)
+            self._compare_pytz(tz, '2011-10-31T03:00')  # No DST
+
+        def test_pytz_paris(self):
+            tz = datefmt.timezone('Europe/Paris')
+            self._tzset('Europe/Paris')
+            self._compare_pytz(tz, '1975-07-01T01:00')  # No DST
+            self._compare_pytz(tz, '1976-03-28T01:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1976-09-26T01:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '2009-03-29T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '2009-10-25T03:00')  # -1:00 (DST end)
+
+        def test_pytz_tokyo(self):
+            tz = datefmt.timezone('Asia/Tokyo')
+            self._tzset('Asia/Tokyo')
+            self._compare_pytz(tz, '1947-07-01T02:00')  # No DST
+            self._compare_pytz(tz, '1948-05-02T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1948-09-11T02:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '1949-04-03T02:00')  # +1:00 (DST start)
+            self._compare_pytz(tz, '1949-09-10T02:00')  # -1:00 (DST end)
+            self._compare_pytz(tz, '1950-07-01T02:00')  # No DST
+
+        def test_pytz_venezuela(self):
+            tz = datefmt.timezone('America/Caracas')
+            self._tzset('America/Caracas')
+            self._compare_pytz(tz, '2006-07-01T00:00')  # No DST
+            self._compare_pytz(tz, '2007-12-09T02:30',  #       (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '2007-12-09T03:00',  # -0:30 (TZ change)
+                               localize=False)
+            self._compare_pytz(tz, '2008-07-01T00:00')  # No DST
+
 
 class LocalTimezoneStrTestCase(unittest.TestCase):
 
@@ -1282,17 +1705,18 @@ class LocalTimezoneStrTestCase(unittest.
 def suite():
     suite = unittest.TestSuite()
     if PytzTestCase:
-        suite.addTest(unittest.makeSuite(PytzTestCase, 'test'))
+        suite.addTest(unittest.makeSuite(PytzTestCase))
     else:
         print "SKIP: utils/tests/datefmt.py (no pytz installed)"
     suite.addTest(unittest.makeSuite(DateFormatTestCase))
     suite.addTest(unittest.makeSuite(UTimestampTestCase))
     suite.addTest(unittest.makeSuite(ISO8601TestCase))
     if I18nDateFormatTestCase:
-        suite.addTest(unittest.makeSuite(I18nDateFormatTestCase, 'test'))
+        suite.addTest(unittest.makeSuite(I18nDateFormatTestCase))
     else:
         print "SKIP: utils/tests/datefmt.py (no babel installed)"
     suite.addTest(unittest.makeSuite(ParseISO8601TestCase))
+    suite.addTest(unittest.makeSuite(ParseDateWithoutBabelTestCase))
     suite.addTest(unittest.makeSuite(ParseRelativeDateTestCase))
     suite.addTest(unittest.makeSuite(ParseDateValidRangeTestCase))
     suite.addTest(unittest.makeSuite(HttpDateTestCase))

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/html.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/html.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/html.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/html.py Sat 
Nov 15 01:14:46 2014
@@ -1,9 +1,24 @@
 # -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-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/.
 
 import unittest
+from genshi.builder import Element, Fragment, tag
 from genshi.input import HTML
 
-from trac.util.html import TracHTMLSanitizer
+import trac.tests.compat
+from trac.core import TracError
+from trac.util.html import TracHTMLSanitizer, find_element, to_fragment
+from trac.util.translation import gettext, tgettext
 
 
 class TracHTMLSanitizerTestCase(unittest.TestCase):
@@ -141,9 +156,95 @@ class TracHTMLSanitizerTestCase(unittest
         self.assertEqual('<div>XSS</div>', unicode(html | TracHTMLSanitizer()))
 
 
+class FindElementTestCase(unittest.TestCase):
+    def test_find_element_with_tag(self):
+        frag = tag(tag.p('Paragraph with a ',
+                   tag.a('link', href='http://www.edgewall.org'),
+                   ' and some ', tag.strong('strong text')))
+        self.assertIsNotNone(find_element(frag, tag='p'))
+        self.assertIsNotNone(find_element(frag, tag='a'))
+        self.assertIsNotNone(find_element(frag, tag='strong'))
+        self.assertIsNone(find_element(frag, tag='input'))
+        self.assertIsNone(find_element(frag, tag='textarea'))
+
+
+class ToFragmentTestCase(unittest.TestCase):
+
+    def test_unicode(self):
+        rv = to_fragment('blah')
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('blah', unicode(rv))
+
+    def test_fragment(self):
+        rv = to_fragment(tag('blah'))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('blah', unicode(rv))
+
+    def test_element(self):
+        rv = to_fragment(tag.p('blah'))
+        self.assertEqual(Element, type(rv))
+        self.assertEqual('<p>blah</p>', unicode(rv))
+
+    def test_tracerror(self):
+        rv = to_fragment(TracError('blah'))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('blah', unicode(rv))
+
+    def test_tracerror_with_fragment(self):
+        message = tag('Powered by ',
+                      tag.a('Trac', href='http://trac.edgewall.org/'))
+        rv = to_fragment(TracError(message))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('Powered by <a href="http://trac.edgewall.org/";>Trac'
+                         '</a>', unicode(rv))
+
+    def test_tracerror_with_element(self):
+        message = tag.p('Powered by ',
+                        tag.a('Trac', href='http://trac.edgewall.org/'))
+        rv = to_fragment(TracError(message))
+        self.assertEqual(Element, type(rv))
+        self.assertEqual('<p>Powered by <a href="http://trac.edgewall.org/";>'
+                         'Trac</a></p>', unicode(rv))
+
+    def test_error(self):
+        rv = to_fragment(ValueError('invalid literal for int(): blah'))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('invalid literal for int(): blah', unicode(rv))
+
+    def test_gettext(self):
+        rv = to_fragment(gettext('%(size)s bytes', size=0))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('0 bytes', unicode(rv))
+
+    def test_tgettext(self):
+        rv = to_fragment(tgettext('Back to %(parent)s',
+                                  parent=tag.a('WikiStart',
+                                               href='http://localhost/')))
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('Back to <a href="http://localhost/";>WikiStart</a>',
+                         unicode(rv))
+
+    def test_tracerror_with_gettext(self):
+        e = TracError(gettext('%(size)s bytes', size=0))
+        rv = to_fragment(e)
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('0 bytes', unicode(rv))
+
+    def test_tracerror_with_tgettext(self):
+        e = TracError(tgettext('Back to %(parent)s',
+                               parent=tag.a('WikiStart',
+                                            href='http://localhost/')))
+        rv = to_fragment(e)
+        self.assertEqual(Fragment, type(rv))
+        self.assertEqual('Back to <a href="http://localhost/";>WikiStart</a>',
+                         unicode(rv))
+
+
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(TracHTMLSanitizerTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(TracHTMLSanitizerTestCase))
+    suite.addTest(unittest.makeSuite(FindElementTestCase))
+    suite.addTest(unittest.makeSuite(ToFragmentTestCase))
     return suite
 
 

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/presentation.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/presentation.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/presentation.py 
(original)
+++ 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/presentation.py 
Sat Nov 15 01:14:46 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C)2006-2009 Edgewall Software
+# Copyright (C) 2006-2013 Edgewall Software
 # Copyright (C) 2006 Christopher Lenz <cml...@gmx.de>
 # All rights reserved.
 #
@@ -32,16 +32,19 @@ class ToJsonTestCase(unittest.TestCase):
                          presentation.to_json("a ' single quote"))
         self.assertEqual(r'"\u003cb\u003e\u0026\u003c/b\u003e"',
                          presentation.to_json('<b>&</b>'))
+        self.assertEqual(r'"\n\r\u2028\u2029"',
+                         presentation.to_json(u'\x0a\x0d\u2028\u2029'))
 
     def test_compound_types(self):
         self.assertEqual('[1,2,[true,false]]',
                          presentation.to_json([1, 2, [True, False]]))
         self.assertEqual(r'{"one":1,"other":[null,0],'
                          r'''"three":[3,"\u0026\u003c\u003e'"],'''
-                         r'"two":2}',
+                         r'"two":2,"\u2028\n":"\u2029\r"}',
                          presentation.to_json({"one": 1, "two": 2,
                                                "other": [None, 0],
-                                               "three": [3, "&<>'"]}))
+                                               "three": [3, "&<>'"],
+                                               u"\u2028\x0a": u"\u2029\x0d"}))
 
 
 def suite():

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/text.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/text.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/text.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/text.py Sat 
Nov 15 01:14:46 2014
@@ -1,31 +1,46 @@
 # -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-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/.
 
+import os
+import socket
 import unittest
 from StringIO import StringIO
 
+import trac.tests.compat
 from trac.util.text import empty, expandtabs, fix_eol, javascript_quote, \
-                           to_js_string, normalize_whitespace, to_unicode, \
-                           text_width, print_table, unicode_quote, \
-                           unicode_quote_plus, unicode_unquote, \
-                           unicode_urlencode, wrap, quote_query_string, \
-                           unicode_to_base64, unicode_from_base64, \
-                           strip_line_ws, stripws, levenshtein_distance
+                           levenshtein_distance, normalize_whitespace, \
+                           print_table, quote_query_string, shorten_line, \
+                           strip_line_ws, stripws, text_width, \
+                           to_js_string, to_unicode, unicode_from_base64, \
+                           unicode_quote, unicode_quote_plus, \
+                           unicode_to_base64, unicode_unquote, \
+                           unicode_urlencode, wrap
 
 
 class ToUnicodeTestCase(unittest.TestCase):
     def test_explicit_charset(self):
         uc = to_unicode('\xc3\xa7', 'utf-8')
-        assert isinstance(uc, unicode)
+        self.assertIsInstance(uc, unicode)
         self.assertEquals(u'\xe7', uc)
 
     def test_explicit_charset_with_replace(self):
         uc = to_unicode('\xc3', 'utf-8')
-        assert isinstance(uc, unicode)
+        self.assertIsInstance(uc, unicode)
         self.assertEquals(u'\xc3', uc)
 
     def test_implicit_charset(self):
         uc = to_unicode('\xc3\xa7')
-        assert isinstance(uc, unicode)
+        self.assertIsInstance(uc, unicode)
         self.assertEquals(u'\xe7', uc)
 
     def test_from_exception_using_unicode_args(self):
@@ -33,26 +48,52 @@ class ToUnicodeTestCase(unittest.TestCas
         try:
             raise ValueError, '%s is not a number.' % u
         except ValueError, e:
-            self.assertEquals(u'\uB144 is not a number.', to_unicode(e))
+            self.assertEqual(u'\uB144 is not a number.', to_unicode(e))
 
     def test_from_exception_using_str_args(self):
         u = u'Das Ger\xe4t oder die Ressource ist belegt'
         try:
             raise ValueError, u.encode('utf-8')
         except ValueError, e:
-            self.assertEquals(u, to_unicode(e))
+            self.assertEqual(u, to_unicode(e))
+
+    def test_from_windows_error(self):
+        try:
+            os.stat('non/existent/file.txt')
+        except OSError, e:
+            uc = to_unicode(e)
+            self.assertIsInstance(uc, unicode, uc)
+            self.assertTrue(uc.startswith('[Error '), uc)
+            self.assertIn(e.strerror.decode('mbcs'), uc)
+
+    def test_from_socket_error(self):
+        for res in socket.getaddrinfo('127.0.0.1', 65536, 0,
+                                      socket.SOCK_STREAM):
+            af, socktype, proto, canonname, sa = res
+            s = socket.socket(af, socktype, proto)
+            try:
+                s.connect(sa)
+            except socket.error, e:
+                uc = to_unicode(e)
+                self.assertIsInstance(uc, unicode, uc)
+                if hasattr(e, 'strerror'):
+                    self.assertIn(e.strerror.decode('mbcs'), uc)
+
+    if os.name != 'nt':
+        del test_from_windows_error
+        del test_from_socket_error
 
 
 class ExpandtabsTestCase(unittest.TestCase):
     def test_empty(self):
         x = expandtabs('', ignoring='\0')
-        self.assertEquals('', x)
+        self.assertEqual('', x)
     def test_ingoring(self):
         x = expandtabs('\0\t', ignoring='\0')
-        self.assertEquals('\0        ', x)
+        self.assertEqual('\0        ', x)
     def test_tabstops(self):
-        self.assertEquals('        ', expandtabs('       \t'))
-        self.assertEquals('                ', expandtabs('\t\t'))
+        self.assertEqual('        ', expandtabs('       \t'))
+        self.assertEqual('                ', expandtabs('\t\t'))
 
 
 class JavascriptQuoteTestCase(unittest.TestCase):
@@ -65,6 +106,8 @@ class JavascriptQuoteTestCase(unittest.T
                          javascript_quote('\x02\x1e'))
         self.assertEqual(r'\u0026\u003c\u003e',
                          javascript_quote('&<>'))
+        self.assertEqual(r'\u2028\u2029',
+                         javascript_quote(u'\u2028\u2029'))
 
 
 class ToJsStringTestCase(unittest.TestCase):
@@ -81,6 +124,8 @@ class ToJsStringTestCase(unittest.TestCa
                          to_js_string(''))
         self.assertEqual('""',
                          to_js_string(None))
+        self.assertEqual(r'"\u2028\u2029"',
+                         to_js_string(u'\u2028\u2029'))
 
 
 class UnicodeQuoteTestCase(unittest.TestCase):
@@ -310,17 +355,17 @@ class UnicodeBase64TestCase(unittest.Tes
 
 class StripwsTestCase(unittest.TestCase):
     def test_stripws(self):
-        self.assertEquals(u'stripws',
-                          stripws(u' \u200b\t\u3000stripws \u200b\t\u2008'))
-        self.assertEquals(u'stripws \u3000\t',
-                          stripws(u'\u200b\t\u2008 stripws \u3000\t',
-                                  trailing=False))
-        self.assertEquals(u' \t\u3000stripws',
-                          stripws(u' \t\u3000stripws \u200b\t\u2008',
-                                  leading=False))
-        self.assertEquals(u' \t\u3000stripws \u200b\t\u2008',
-                          stripws(u' \t\u3000stripws \u200b\t\u2008',
-                                  leading=False, trailing=False))
+        self.assertEqual(u'stripws',
+                         stripws(u' \u200b\t\u3000stripws \u200b\t\u2008'))
+        self.assertEqual(u'stripws \u3000\t',
+                         stripws(u'\u200b\t\u2008 stripws \u3000\t',
+                                 trailing=False))
+        self.assertEqual(u' \t\u3000stripws',
+                         stripws(u' \t\u3000stripws \u200b\t\u2008',
+                                 leading=False))
+        self.assertEqual(u' \t\u3000stripws \u200b\t\u2008',
+                         stripws(u' \t\u3000stripws \u200b\t\u2008',
+                                 leading=False, trailing=False))
 
 
 
@@ -333,22 +378,41 @@ class LevenshteinDistanceTestCase(unitte
         self.assertEqual(0, levenshtein_distance('milestone', 'milestone'))
 
 
+class ShortenLineTestCase(unittest.TestCase):
+
+    def test_less_than_maxlen(self):
+        text = '123456789'
+        self.assertEqual(text, shorten_line(text, 10))
+
+    def test_equalto_maxlen(self):
+        text = '1234567890'
+        self.assertEqual(text, shorten_line(text, 10))
+
+    def test_greater_than_maxlen(self):
+        text = 'word word word word'
+        self.assertEqual('word word ...', shorten_line(text, 15))
+        text = 'abcdefghij'
+        self.assertEqual('abcde ...', shorten_line(text, 9))
+
+
+
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(ToUnicodeTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(ExpandtabsTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(UnicodeQuoteTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(JavascriptQuoteTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(ToJsStringTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(QuoteQueryStringTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(WhitespaceTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(TextWidthTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(PrintTableTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(WrapTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(FixEolTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(UnicodeBase64TestCase, 'test'))
-    suite.addTest(unittest.makeSuite(StripwsTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(LevenshteinDistanceTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(ToUnicodeTestCase))
+    suite.addTest(unittest.makeSuite(ExpandtabsTestCase))
+    suite.addTest(unittest.makeSuite(UnicodeQuoteTestCase))
+    suite.addTest(unittest.makeSuite(JavascriptQuoteTestCase))
+    suite.addTest(unittest.makeSuite(ToJsStringTestCase))
+    suite.addTest(unittest.makeSuite(QuoteQueryStringTestCase))
+    suite.addTest(unittest.makeSuite(WhitespaceTestCase))
+    suite.addTest(unittest.makeSuite(TextWidthTestCase))
+    suite.addTest(unittest.makeSuite(PrintTableTestCase))
+    suite.addTest(unittest.makeSuite(WrapTestCase))
+    suite.addTest(unittest.makeSuite(FixEolTestCase))
+    suite.addTest(unittest.makeSuite(UnicodeBase64TestCase))
+    suite.addTest(unittest.makeSuite(StripwsTestCase))
+    suite.addTest(unittest.makeSuite(LevenshteinDistanceTestCase))
+    suite.addTest(unittest.makeSuite(ShortenLineTestCase))
     return suite
 
 if __name__ == '__main__':

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/text.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/text.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/text.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/text.py Sat Nov 
15 01:14:46 2014
@@ -61,6 +61,13 @@ def to_unicode(text, charset=None):
         except UnicodeDecodeError:
             return unicode(text, 'latin1')
     elif isinstance(text, Exception):
+        if os.name == 'nt' and isinstance(text, (OSError, IOError)):
+            # the exception might have a localized error string encoded with
+            # ANSI codepage if OSError and IOError on Windows
+            try:
+                return unicode(str(text), 'mbcs')
+            except UnicodeError:
+                pass
         # two possibilities for storing unicode strings in exception data:
         try:
             # custom __str__ method on the exception (e.g. PermissionError)
@@ -131,10 +138,10 @@ def strip_line_ws(text, leading=True, tr
 
 _js_quote = {'\\': '\\\\', '"': '\\"', '\b': '\\b', '\f': '\\f',
              '\n': '\\n', '\r': '\\r', '\t': '\\t', "'": "\\'"}
-for i in range(0x20) + [ord(c) for c in '&<>']:
-    _js_quote.setdefault(chr(i), '\\u%04x' % i)
-_js_quote_re = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t\'&<>]')
-_js_string_re = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t&<>]')
+for i in range(0x20) + [ord(c) for c in u'&<>\u2028\u2029']:
+    _js_quote.setdefault(unichr(i), '\\u%04x' % i)
+_js_quote_re = re.compile(ur'[\x00-\x1f\\"\b\f\n\r\t\'&<>\u2028\u2029]')
+_js_string_re = re.compile(ur'[\x00-\x1f\\"\b\f\n\r\t&<>\u2028\u2029]')
 
 
 def javascript_quote(text):
@@ -221,24 +228,27 @@ def quote_query_string(text):
 
 
 def to_utf8(text, charset='latin1'):
-    """Convert a string to UTF-8, assuming the encoding is either UTF-8, ISO
-    Latin-1, or as specified by the optional `charset` parameter.
+    """Convert a string to an UTF-8 `str` object.
 
-    .. deprecated :: 0.10
-       You should use `unicode` strings only.
-    """
-    try:
-        # Do nothing if it's already utf-8
-        u = unicode(text, 'utf-8')
-        return text
-    except UnicodeError:
+    If the input is not an `unicode` object, we assume the encoding is
+    already UTF-8, ISO Latin-1, or as specified by the optional
+    *charset* parameter.
+    """
+    if isinstance(text, unicode):
+        u = text
+    else:
         try:
-            # Use the user supplied charset if possible
-            u = unicode(text, charset)
+            # Do nothing if it's already utf-8
+            u = unicode(text, 'utf-8')
+            return text
         except UnicodeError:
-            # This should always work
-            u = unicode(text, 'latin1')
-        return u.encode('utf-8')
+            try:
+                # Use the user supplied charset if possible
+                u = unicode(text, charset)
+            except UnicodeError:
+                # This should always work
+                u = unicode(text, 'latin1')
+    return u.encode('utf-8')
 
 
 class unicode_passwd(unicode):
@@ -402,17 +412,19 @@ def print_table(data, headers=None, sep=
 
 
 def shorten_line(text, maxlen=75):
-    """Truncates content to at most `maxlen` characters.
+    """Truncates `text` to length less than or equal to `maxlen` characters.
 
     This tries to be (a bit) clever and attempts to find a proper word
     boundary for doing so.
     """
-    if len(text or '') < maxlen:
+    if len(text or '') <= maxlen:
         return text
-    cut = max(text.rfind(' ', 0, maxlen), text.rfind('\n', 0, maxlen))
+    suffix = ' ...'
+    maxtextlen = maxlen - len(suffix)
+    cut = max(text.rfind(' ', 0, maxtextlen), text.rfind('\n', 0, maxtextlen))
     if cut < 0:
-        cut = maxlen
-    return text[:cut] + ' ...'
+        cut = maxtextlen
+    return text[:cut] + suffix
 
 
 class UnicodeTextWrapper(textwrap.TextWrapper):

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/util/translation.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/translation.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/translation.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/translation.py 
Sat Nov 15 01:14:46 2014
@@ -146,17 +146,18 @@ try:
                 self._activate_failed = True
                 return
             t = Translations.load(locale_dir, locale or 'en_US')
-            if not t or t.__class__ is NullTranslations:
+            if not isinstance(t, Translations):
                 t = self._null_translations
             else:
-                t.add(Translations.load(locale_dir, locale or 'en_US',
-                                        'tracini'))
+                self._add(t, Translations.load(locale_dir, locale or 'en_US',
+                                               'tracini'))
                 if env_path:
                     with self._plugin_domains_lock:
                         domains = self._plugin_domains.get(env_path, {})
                         domains = domains.items()
                     for domain, dirname in domains:
-                        t.add(Translations.load(dirname, locale, domain))
+                        self._add(t, Translations.load(dirname, locale,
+                                                       domain))
             self._current.translations = t
             self._activate_failed = False
 
@@ -184,6 +185,12 @@ try:
             return self._current.translations is not None \
                    or self._activate_failed
 
+        # Internal methods
+
+        def _add(self, t, translations):
+            if isinstance(translations, Translations):
+                t.add(translations)
+
         # Delegated methods
 
         def __getattr__(self, name):
@@ -335,21 +342,37 @@ try:
         translations are available.
         """
         try:
-            return [dirname for dirname
-                    in pkg_resources.resource_listdir('trac', 'locale')
-                    if '.' not in dirname]
+            locales = [dirname for dirname
+                       in pkg_resources.resource_listdir('trac', 'locale')
+                       if '.' not in dirname
+                       and pkg_resources.resource_exists(
+                        'trac', 'locale/%s/LC_MESSAGES/messages.mo' % dirname)]
+            return locales
         except Exception:
             return []
 
     def get_negotiated_locale(preferred_locales):
         def normalize(locale_ids):
             return [id.replace('-', '_') for id in locale_ids if id]
-        return Locale.negotiate(normalize(preferred_locales),
-                                normalize(get_available_locales()))
+        available_locales = get_available_locales()
+        if 'en_US' not in available_locales:
+            available_locales.append('en_US')
+        locale = Locale.negotiate(normalize(preferred_locales),
+                                  normalize(available_locales))
+        if locale and str(locale) not in available_locales:
+            # The list of get_available_locales() must include locale
+            # identifier from str(locale), but zh_* don't be included after
+            # Babel 1.0. Avoid expanding zh_* to zh_Hans_CN and zh_Hant_TW
+            # to clear "script" property of Locale instance. See #11258.
+            locale._data  # load localedata before clear script property
+            locale.script = None
+            assert str(locale) in available_locales
+        return locale
 
     has_babel = True
 
 except ImportError: # fall back on 0.11 behavior, i18n functions are no-ops
+    Locale = None
     gettext = _ = gettext_noop
     dgettext = dgettext_noop
     ngettext = ngettext_noop

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/__init__.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/__init__.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/__init__.py 
(original)
+++ 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/__init__.py 
Sat Nov 15 01:14:46 2014
@@ -1 +1,14 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2005-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.com/license.html.
+#
+# 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/.
+
 from trac.versioncontrol.api import *

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/admin.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/admin.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/admin.py 
(original)
+++ 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/admin.py 
Sat Nov 15 01:14:46 2014
@@ -176,13 +176,11 @@ class RepositoryAdminPanel(Component):
     # IAdminPanelProvider methods
 
     def get_admin_panels(self, req):
-        if 'VERSIONCONTROL_ADMIN' in req.perm:
+        if 'VERSIONCONTROL_ADMIN' in req.perm('admin', 
'versioncontrol/repository'):
             yield ('versioncontrol', _('Version Control'), 'repository',
                    _('Repositories'))
 
     def render_admin_panel(self, req, category, page, path_info):
-        req.perm.require('VERSIONCONTROL_ADMIN')
-
         # Retrieve info for all repositories
         rm = RepositoryManager(self.env)
         all_repos = rm.get_all_repositories()
@@ -202,39 +200,42 @@ class RepositoryAdminPanel(Component):
                 elif db_provider and req.args.get('save'):
                     # Modify repository
                     changes = {}
+                    valid = True
                     for field in db_provider.repository_attrs:
                         value = normalize_whitespace(req.args.get(field))
                         if (value is not None or field == 'hidden') \
                                 and value != info.get(field):
                             changes[field] = value
-                    if 'dir' in changes \
-                            and not self._check_dir(req, changes['dir']):
-                        changes = {}
-                    if changes:
+                    if 'dir' in changes and not \
+                            self._check_dir(req, changes['dir']):
+                        valid = False
+                    if valid and changes:
                         db_provider.modify_repository(reponame, changes)
                         add_notice(req, _('Your changes have been saved.'))
-                    name = req.args.get('name')
-                    resync = tag.tt('trac-admin $ENV repository resync "%s"'
-                                    % (name or '(default)'))
-                    if 'dir' in changes:
-                        msg = tag_('You should now run %(resync)s to '
-                                   'synchronize Trac with the repository.',
-                                   resync=resync)
-                        add_notice(req, msg)
-                    elif 'type' in changes:
-                        msg = tag_('You may have to run %(resync)s to '
-                                   'synchronize Trac with the repository.',
-                                   resync=resync)
-                        add_notice(req, msg)
-                    if name and name != path_info and not 'alias' in info:
-                        cset_added = tag.tt('trac-admin $ENV changeset '
-                                            'added "%s" $REV'
-                                            % (name or '(default)'))
-                        msg = tag_('You will need to update your post-commit '
-                                   'hook to call %(cset_added)s with the new '
-                                   'repository name.', cset_added=cset_added)
-                        add_notice(req, msg)
-                    if changes:
+                        name = req.args.get('name')
+                        resync = tag.tt('trac-admin $ENV repository resync '
+                                        '"%s"' % (name or '(default)'))
+                        if 'dir' in changes:
+                            msg = tag_('You should now run %(resync)s to '
+                                       'synchronize Trac with the repository.',
+                                       resync=resync)
+                            add_notice(req, msg)
+                        elif 'type' in changes:
+                            msg = tag_('You may have to run %(resync)s to '
+                                       'synchronize Trac with the repository.',
+                                       resync=resync)
+                            add_notice(req, msg)
+                        if name and name != path_info and not 'alias' in info:
+                            cset_added = tag.tt('trac-admin $ENV changeset '
+                                                'added "%s" $REV'
+                                                % (name or '(default)'))
+                            msg = tag_('You will need to update your '
+                                       'post-commit hook to call '
+                                       '%(cset_added)s with the new '
+                                       'repository name.',
+                                       cset_added=cset_added)
+                            add_notice(req, msg)
+                    if valid:
                         req.redirect(req.href.admin(category, page))
 
             Chrome(self.env).add_wiki_toolbars(req)
@@ -253,7 +254,12 @@ class RepositoryAdminPanel(Component):
                         add_warning(req, _('Missing arguments to add a '
                                            'repository.'))
                     elif self._check_dir(req, dir):
-                        db_provider.add_repository(name, dir, type_)
+                        try:
+                            db_provider.add_repository(name, dir, type_)
+                        except self.env.db_exc.IntegrityError:
+                            name = name or '(default)'
+                            raise TracError(_('The repository "%(name)s" '
+                                              'already exists.', name=name))
                         name = name or '(default)'
                         add_notice(req, _('The repository "%(name)s" has been '
                                           'added.', name=name))
@@ -277,7 +283,12 @@ class RepositoryAdminPanel(Component):
                     name = req.args.get('name')
                     alias = req.args.get('alias')
                     if name is not None and alias is not None:
-                        db_provider.add_alias(name, alias)
+                        try:
+                            db_provider.add_alias(name, alias)
+                        except self.env.db_exc.IntegrityError:
+                            raise TracError(_('The alias "%(name)s" already '
+                                              'exists.',
+                                              name=name or '(default)'))
                         add_notice(req, _('The alias "%(name)s" has been '
                                           'added.', name=name or '(default)'))
                         req.redirect(req.href.admin(category, page))

Modified: 
bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/api.py
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/api.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/api.py 
(original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/versioncontrol/api.py 
Sat Nov 15 01:14:46 2014
@@ -24,7 +24,7 @@ from trac.config import ConfigSection, L
 from trac.core import *
 from trac.resource import IResourceManager, Resource, ResourceNotFound
 from trac.util.concurrency import threading
-from trac.util.text import printout, to_unicode
+from trac.util.text import printout, to_unicode, exception_to_unicode
 from trac.util.translation import _
 from trac.web.api import IRequestFilter
 
@@ -250,9 +250,18 @@ class DbRepositoryProvider(Component):
         """Modify attributes of a repository."""
         if is_default(reponame):
             reponame = ''
+        new_reponame = changes.get('name', reponame)
+        if is_default(new_reponame):
+            new_reponame = ''
         rm = RepositoryManager(self.env)
         with self.env.db_transaction as db:
             id = rm.get_repository_id(reponame)
+            if reponame != new_reponame:
+                if db("""SELECT id FROM repository WHERE name='name' AND
+                         value=%s""", (new_reponame,)):
+                    raise TracError(_('The repository "%(name)s" already '
+                                      'exists.',
+                                      name=new_reponame or '(default)'))
             for (k, v) in changes.iteritems():
                 if k not in self.repository_attrs:
                     continue
@@ -353,7 +362,22 @@ class RepositoryManager(Component):
                         _("Can't synchronize with repository \"%(name)s\" "
                           "(%(error)s). Look in the Trac log for more "
                           "information.", name=reponame or '(default)',
-                          error=to_unicode(e.message)))
+                          error=to_unicode(e)))
+                except Exception, e:
+                    add_warning(req,
+                        _("Failed to sync with repository \"%(name)s\": "
+                          "%(error)s; repository information may be out of "
+                          "date. Look in the Trac log for more information "
+                          "including mitigation strategies.",
+                          name=reponame or '(default)', error=to_unicode(e)))
+                    self.log.error(
+                        "Failed to sync with repository \"%s\"; You may be "
+                        "able to reduce the impact of this issue by "
+                        "configuring [trac] repository_sync_per_request; see "
+                        "http://trac.edgewall.org/wiki/TracRepositoryAdmin";
+                        "#ExplicitSync for more detail: %s",
+                        reponame or '(default)',
+                        exception_to_unicode(e, traceback=True))
                 self.log.info("Synchronized '%s' repository in %0.2f seconds",
                               reponame or '(default)', time.time() - start)
         return handler
@@ -400,6 +424,8 @@ class RepositoryManager(Component):
             return _('%(kind)s %(id)s%(at_version)s%(in_repo)s',
                      kind=kind, id=id, at_version=version, in_repo=in_repo)
         elif resource.realm == 'repository':
+            if not resource.id:
+                return _("Default repository")
             return _("Repository %(repo)s", repo=resource.id)
 
     def get_resource_url(self, resource, href, **kwargs):
@@ -502,8 +528,8 @@ class RepositoryManager(Component):
 
         This will create and save a new id if none is found.
 
-        \note: this should probably be renamed as we're dealing
-               exclusively with *db* repository ids here.
+        Note: this should probably be renamed as we're dealing
+              exclusively with *db* repository ids here.
         """
         with self.env.db_transaction as db:
             for id, in db(
@@ -631,8 +657,8 @@ class RepositoryManager(Component):
         The supported events are the names of the methods defined in the
         `IRepositoryChangeListener` interface.
         """
-        self.log.debug("Event %s on %s for changesets %r",
-                       event, reponame, revs)
+        self.log.debug("Event %s on repository '%s' for changesets %r",
+                       event, reponame or '(default)', revs)
 
         # Notify a repository by name, and all repositories with the same
         # base, or all repositories by base or by repository dir
@@ -667,8 +693,12 @@ class RepositoryManager(Component):
                         repos.sync_changeset(rev)
                         changeset = repos.get_changeset(rev)
                     except NoSuchChangeset:
+                        self.log.debug(
+                            "No changeset '%s' found in repository '%s'. "
+                            "Skipping subscribers for event %s",
+                            rev, repos.reponame or '(default)', event)
                         continue
-                self.log.debug("Event %s on %s for revision %s",
+                self.log.debug("Event %s on repository '%s' for revision '%s'",
                                event, repos.reponame or '(default)', rev)
                 for listener in self.change_listeners:
                     getattr(listener, event)(repos, changeset, *args)
@@ -998,6 +1028,23 @@ class Node(object):
         """
         raise NotImplementedError
 
+    def get_processed_content(self, keyword_substitution=True, eol_hint=None):
+        """Return a stream for reading the content of the node, with some
+        standard processing applied.
+
+        :param keyword_substitution: if `True`, meta-data keywords
+            present in the content like ``$Rev$`` are substituted
+            (which keyword are substituted and how they are
+            substituted is backend specific)
+
+        :param eol_hint: which style of line ending is expected if
+            `None` was explicitly specified for the file itself in
+            the version control backend (for example in Subversion,
+            if it was set to ``'native'``).  It can be `None`,
+            ``'LF'``, ``'CR'`` or ``'CRLF'``.
+        """
+        return self.get_content()
+
     def get_entries(self):
         """Generator that yields the immediate child entries of a directory.
 


Reply via email to