Commits

strontium committed 16a6b66

Add unittests to replace doctests for catalog.py. All tests pass for catalog.py in Py2.6,2.7 and 3.2
Fixup unicode string converting in catalog.py not needed in py3
replace util.py odict class with a new class using Python 3.1+ collection.OrderedDict as original odict did not work in Py3

Comments (0)

Files changed (3)

babel/messages/catalog.py

             # special treatment for the header message
             def _parse_header(header_string):
                 # message_from_string only works for str, not for unicode
-                headers = message_from_string(header_string.encode('utf8'))
+                if sys.version_info < (3, 0):
+                  header_string = header_string.encode('utf8')
+                headers = message_from_string(header_string)
                 decoded_headers = {}
                 for name, value in headers.items():
-                    name = name.decode('utf8')
-                    value = value.decode('utf8')
+                    if sys.version_info < (3, 0):
+                        name = name.decode('utf8')
+                        value = value.decode('utf8')
                     decoded_headers[name] = value
                 return decoded_headers
             self.mime_headers = _parse_header(message.string).items()

babel/messages/tests/catalog.py

 import datetime
 import doctest
 import unittest
+import re
 
 from babel.messages import catalog
+from babel.messages.catalog import Catalog, Message
+from babel.util import UTC
+import sys
+
+if sys.version_info >= (3, 0):
+  #Python 3 no need for u''
+  py2u = '' 
+else:
+  py2u = 'u'
 
 
 class MessageTestCase(unittest.TestCase):
             if key in ('POT-Creation-Date', 'PO-Revision-Date'):
                 self.assertEqual(value, '2009-03-09 15:47-0700')
 
+
+class messagesCatalogDocTest(unittest.TestCase):
+
+    def test_messages_catalog_Catalog__setitem__(self):
+        # Add or update the message with the specified ID.
+        catalog = Catalog()
+        catalog[u'foo'] = Message(u'foo')
+        self.assertEqual(repr(catalog[u'foo']), '<Message %s\'foo\' (flags: [])>' % py2u)
+        catalog = Catalog()
+        catalog[u'foo'] = Message(u'foo', locations=[('main.py', 1)])
+        self.assertEqual(catalog[u'foo'].locations, [('main.py', 1)])
+        catalog[u'foo'] = Message(u'foo', locations=[('utils.py', 5)])
+        self.assertEqual(catalog[u'foo'].locations, [('main.py', 1), ('utils.py', 5)])
+        
+    def test_messages_catalog_Catalog_add(self):
+        # Add or update the message with the specified ID.
+        catalog = Catalog()
+        r = catalog.add(u'foo')
+        matched = re.match('^<Message .*>$', repr(r))
+        self.assertNotEqual(matched, None)
+        self.assertEqual(repr(catalog[u'foo']), '<Message %s\'foo\' (flags: [])>' % py2u)
+        
+    def test_messages_catalog_Catalog_header_comment(self):
+        # The header comment for the catalog.
+        catalog = Catalog(project='Foobar', version='1.0', copyright_holder='Foo Company')
+        header_comment_regexp = \
+u"""\
+^# Translations template for Foobar\.$(?:\\n|\\r\\n?)\
+^# Copyright \(C\) .*? Foo Company$(?:\\n|\\r\\n?)\
+^# This file is distributed under the same license as the Foobar project\.$(?:\\n|\\r\\n?)\
+^# FIRST AUTHOR <EMAIL@ADDRESS>, .*$(?:\\n|\\r\\n?)\
+^#\
+"""
+        matched = re.match(header_comment_regexp, catalog.header_comment, re.MULTILINE)
+        self.assertNotEqual(matched, None)
+
+        catalog = Catalog(project='Foobar', version='1.0', copyright_holder='Foo Company')
+        catalog.header_comment = \
+"""\
+# The POT for my really cool PROJECT project.
+# Copyright (C) 1990-2003 ORGANIZATION
+# This file is distributed under the same license as the PROJECT
+# project.
+#
+"""
+        header_comment_regexp = \
+"""\
+^# The POT for my really cool Foobar project.$(?:\\n|\\r\\n?)\
+^# Copyright \(C\) 1990-2003 Foo Company$(?:\\n|\\r\\n?)\
+^# This file is distributed under the same license as the Foobar$(?:\\n|\\r\\n?)\
+^# project.$(?:\\n|\\r\\n?)\
+^#\
+"""
+        matched = re.match(header_comment_regexp, catalog.header_comment, re.MULTILINE)
+        self.assertNotEqual(matched, None)
+
+    def test_messages_catalog_Catalog_mime_headers(self):
+        # The MIME headers of the catalog, used for the special ``msgid ""`` entry.
+        created = datetime.datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
+        catalog = Catalog(project='Foobar', version='1.0',
+                          creation_date=created)
+        headers = ""
+        for name, value in catalog.mime_headers:
+            headers += '%s: %s\n' % (name, value)
+        mime_header_regexp = \
+u"""\
+^Project-Id-Version: Foobar 1\.0$(?:\\n|\\r\\n?)\
+^Report-Msgid-Bugs-To: EMAIL@ADDRESS$(?:\\n|\\r\\n?)\
+^POT-Creation-Date: 1990-04-01 15:30\+0000$(?:\\n|\\r\\n?)\
+^PO-Revision-Date: YEAR-MO-DA HO:MI\+ZONE$(?:\\n|\\r\\n?)\
+^Last-Translator: FULL NAME <EMAIL@ADDRESS>$(?:\\n|\\r\\n?)\
+^Language-Team: LANGUAGE <LL@li\.org>$(?:\\n|\\r\\n?)\
+^MIME-Version: 1\.0$(?:\\n|\\r\\n?)\
+^Content-Type: text/plain; charset=utf-8$(?:\\n|\\r\\n?)\
+^Content-Transfer-Encoding: 8bit$(?:\\n|\\r\\n?)\
+^Generated-By: Babel .*$(?:\\n|\\r\\n?)\
+"""
+        matched = re.match(mime_header_regexp, headers, re.MULTILINE)
+        self.assertNotEqual(matched, None)
+
+        revised = datetime.datetime(1990, 8, 3, 12, 0, tzinfo=UTC)
+        catalog = Catalog(locale='de_DE', project='Foobar', version='1.0',
+                          creation_date=created, revision_date=revised,
+                          last_translator='John Doe <jd@example.com>',
+                          language_team='de_DE <de@example.com>')
+        headers = ""
+        for name, value in catalog.mime_headers:
+            headers += '%s: %s\n' % (name, value)
+        mime_header_regexp = \
+u"""\
+^Project-Id-Version: Foobar 1\.0$(?:\\n|\\r\\n?)\
+^Report-Msgid-Bugs-To: EMAIL@ADDRESS$(?:\\n|\\r\\n?)\
+^POT-Creation-Date: 1990-04-01 15:30\+0000$(?:\\n|\\r\\n?)\
+^PO-Revision-Date: 1990-08-03 12:00\+0000$(?:\\n|\\r\\n?)\
+^Last-Translator: John Doe <jd@example\.com>$(?:\\n|\\r\\n?)\
+^Language-Team: de_DE <de@example\.com>$(?:\\n|\\r\\n?)\
+^Plural-Forms: nplurals=2; plural=\(n != 1\)$(?:\\n|\\r\\n?)\
+^MIME-Version: 1.0$(?:\\n|\\r\\n?)\
+^Content-Type: text/plain; charset=utf-8$(?:\\n|\\r\\n?)\
+^Content-Transfer-Encoding: 8bit$(?:\\n|\\r\\n?)\
+^Generated-By: Babel .*$(?:\\n|\\r\\n?)\
+"""
+        matched = re.match(mime_header_regexp, headers, re.MULTILINE)
+        self.assertNotEqual(matched, None)
+        
+    def test_messages_catalog_Catalog_num_plurals(self):
+        # The number of plurals used by the catalog or locale.
+        self.assertEqual(Catalog(locale='en').num_plurals, 2)
+        self.assertEqual(Catalog(locale='ga').num_plurals, 3)
+
+    def test_messages_catalog_Catalog_plural_expr(self):
+        #The plural expression used by the catalog or locale.
+        self.assertEqual(Catalog(locale='en').plural_expr, '(n != 1)')
+        self.assertEqual(Catalog(locale='ga').plural_expr, '(n==1 ? 0 : n==2 ? 1 : 2)')
+
+    def test_messages_catalog_Catalog_plural_forms(self):
+        # Return the plural forms declaration for the locale.
+        self.assertEqual(Catalog(locale='en').plural_forms, 'nplurals=2; plural=(n != 1)')
+        self.assertEqual(Catalog(locale='pt_BR').plural_forms, 'nplurals=2; plural=(n > 1)')
+
+    def test_messages_catalog_Catalog_update(self):
+        # Update the catalog based on the given template catalog.
+        template = Catalog()
+        r = template.add('green', locations=[('main.py', 99)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+        r = template.add('blue', locations=[('main.py', 100)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+        r = template.add(('salad', 'salads'), locations=[('util.py', 42)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+        catalog = Catalog(locale='de_DE')
+        r = catalog.add('blue', u'blau', locations=[('main.py', 98)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+        r = catalog.add('head', u'Kopf', locations=[('util.py', 33)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+        r = catalog.add(('salad', 'salads'), (u'Salat', u'Salate'),
+                        locations=[('util.py', 38)])
+        self.assertNotEqual(re.match('^<Message .*>$', repr(r)), None)
+
+        catalog.update(template)
+        self.assertEqual(len(catalog), 3)
+
+        msg1 = catalog['green']
+        self.assertEqual(msg1.string, None)
+        self.assertEqual(msg1.locations, [('main.py', 99)])
+
+        msg2 = catalog['blue']
+        self.assertEqual(msg2.string, u'blau' )
+        self.assertEqual(msg2.locations, [('main.py', 100)])
+
+        msg3 = catalog['salad']
+        self.assertEqual(msg3.string, (u'Salat', u'Salate'))
+        self.assertEqual(msg3.locations, [('util.py', 42)])
+        self.assertEqual('head' in catalog, False)
+        self.assertEqual(repr(catalog.obsolete.values()), '[<Message \'head\' (flags: [])>]')
+
+    def test_messages_catalog_Message_fuzzy(self):
+        # Whether the translation is fuzzy.
+        self.assertEqual(Message('foo').fuzzy, False)
+        msg = Message('foo', 'foo', flags=['fuzzy'])
+        self.assertEqual(msg.fuzzy, True)
+        self.assertEqual(repr(msg), '<Message \'foo\' (flags: [\'fuzzy\'])>')
+
+    def test_messages_catalog_Message_pluralizable(self):
+        # Whether the message is plurizable.
+        self.assertEqual(Message('foo').pluralizable, False)
+        self.assertEqual(Message(('foo', 'bar')).pluralizable, True)
+
+    def test_messages_catalog_Message_python_format(self):
+        # Whether the message contains Python-style parameters.
+        self.assertEqual(Message('foo %(name)s bar').python_format, True)
+        self.assertEqual(Message(('foo %(name)s', 'foo %(name)s')).python_format, True)
+
 def suite():
     suite = unittest.TestSuite()
     import sys
             suite.addTest(doctest.DocTestSuite(catalog, optionflags=doctest.ELLIPSIS))
         else:
             suite.addTest(doctest.DocTestSuite(catalog))
+    suite.addTest(unittest.makeSuite(messagesCatalogDocTest))
     suite.addTest(unittest.makeSuite(MessageTestCase))
     suite.addTest(unittest.makeSuite(CatalogTestCase))
     return suite
 import textwrap
 import time
 from itertools import izip, imap
+import sys
 
 missing = object()
 
                           break_long_words=False)
     return wrapper.wrap(text)
 
-
-class odict(dict):
+if sys.version_info >= (3, 1):
+  import collections
+  class odict(collections.OrderedDict):
+    """Ordered dict implementation.
+    As per PEP 372, an ordered dict was added to Python 3.1 and above
+    Use that here, as the odict below did not work for py3.2
+    """
+    def __init__(self, data=None):
+        collections.OrderedDict.__init__(self, data or {})
+    
+else:
+  class odict(dict):
     """Ordered dict implementation.
     
     :see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
             return dict.pop(self, key)
         elif key not in self:
             return default
+        # In py3 keys are views
         self._keys.remove(key)
         return dict.pop(self, key, default)