# -*- coding: ISO-8859-1 -*- ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Tests for TALInterpreter. $Id: test_talinterpreter.py 39848 2005-11-02 18:34:38Z philikon $ """ import sys import unittest from StringIO import StringIO from TAL.TALDefs import METALError, I18NError from TAL.HTMLTALParser import HTMLTALParser from TAL.TALParser import TALParser from TAL.TALInterpreter import TALInterpreter from TAL.DummyEngine import DummyEngine, DummyTranslationService from TAL.TALInterpreter import interpolate from TAL.tests import utils from zope.i18nmessageid import Message class TestCaseBase(unittest.TestCase): def _compile(self, source): parser = HTMLTALParser() parser.parseString(source) program, macros = parser.getCode() return program, macros class MacroErrorsTestCase(TestCaseBase): def setUp(self): dummy, macros = self._compile('

Booh

') self.macro = macros['M'] self.engine = DummyEngine(macros) program, dummy = self._compile('

Bah

') self.interpreter = TALInterpreter(program, {}, self.engine) def tearDown(self): try: self.interpreter() except METALError: pass else: self.fail("Expected METALError") def test_mode_error(self): self.macro[1] = ("mode", "duh") def test_version_error(self): self.macro[0] = ("version", "duh") class I18NCornerTestCase(TestCaseBase): def setUp(self): self.engine = DummyEngine() self.engine.setLocal('foo', Message('FoOvAlUe', 'default')) self.engine.setLocal('bar', 'BaRvAlUe') self.engine.setLocal('raw', ' \tRaW\n ') self.engine.setLocal('noxlt', Message("don't translate me")) def _check(self, program, expected): result = StringIO() self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() self.assertEqual(expected, result.getvalue()) def test_simple_messageid_translate(self): # This test is mainly here to make sure our DummyEngine works # correctly. program, macros = self._compile('') self._check(program, 'FOOVALUE\n') program, macros = self._compile('') self._check(program, 'FOOVALUE\n') def test_replace_with_messageid_and_i18nname(self): program, macros = self._compile( '
' '' '
') self._check(program, '
FOOVALUE
\n') def test_pythonexpr_replace_with_messageid_and_i18nname(self): program, macros = self._compile( '
' '' '
') self._check(program, '
FOOVALUE
\n') def test_structure_replace_with_messageid_and_i18nname(self): program, macros = self._compile( '
' '' '
') self._check(program, '
FOOVALUE
\n') def test_complex_replace_with_messageid_and_i18nname(self): program, macros = self._compile( '
' '' '' '' '
') self._check(program, '
FOOVALUE
\n') def test_content_with_messageid_and_i18nname(self): program, macros = self._compile( '
' '' '
') self._check(program, '
FOOVALUE
\n') def test_content_with_messageid_and_i18nname_and_i18ntranslate(self): # Let's tell the user this is incredibly silly! self.assertRaises( I18NError, self._compile, '') def test_content_with_plaintext_and_i18nname_and_i18ntranslate(self): # Let's tell the user this is incredibly silly! self.assertRaises( I18NError, self._compile, 'green') def test_translate_static_text_as_dynamic(self): program, macros = self._compile( '
This is text for ' '.' '
') self._check(program, '
THIS IS TEXT FOR BARVALUE.
\n') def test_translate_static_text_as_dynamic_from_bytecode(self): program = [('version', '1.5'), ('mode', 'html'), ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': ''}), ('startTag', ('div', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextOffset', ('This is text for ', 17)), ('setPosition', (1, 40)), ('beginScope', {'tal:content': 'bar', 'i18n:name': 'bar_name', 'i18n:translate': ''}), ('i18nVariable', ('bar_name', [('startTag', ('span', [('i18n:translate', '', 'i18n'), ('tal:content', 'bar', 'tal'), ('i18n:name', 'bar_name', 'i18n')])), ('insertTranslation', ('', [('insertText', ('$bar$', []))])), ('rawtextOffset', ('
', 7))], None, 0)), ('endScope', ()), ('rawtextOffset', ('.', 1))])), ('endScope', ()), ('rawtextOffset', ('', 6)) ] self._check(program, '
THIS IS TEXT FOR BARVALUE.
\n') def _getCollectingTranslationDomain(self): class CollectingTranslationService(DummyTranslationService): data = [] def translate(self, domain, msgid, mapping=None, context=None, target_language=None, default=None): self.data.append((msgid, mapping)) return DummyTranslationService.translate( self, domain, msgid, mapping, context, target_language, default) xlatsvc = CollectingTranslationService() self.engine.translationService = xlatsvc return xlatsvc def test_for_correct_msgids(self): xlatdmn = self._getCollectingTranslationDomain() result = StringIO() program, macros = self._compile( '
This is text for ' '.
') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = list(xlatdmn.data) msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual('BaRvAlUe', msgids[0][0]) self.assertEqual('This is text for ${bar_name}.', msgids[1][0]) self.assertEqual({'bar_name': 'BARVALUE'}, msgids[1][1]) self.assertEqual( '
THIS IS TEXT FOR BARVALUE.
\n', result.getvalue()) def test_for_raw_msgids(self): # Test for Issue 314: i18n:translate removes line breaks from #
...
contents # HTML mode xlatdmn = self._getCollectingTranslationDomain() result = StringIO() program, macros = self._compile( '
This is text\n' ' \tfor\n div.
' '
 This is text\n'
            ' \tfor\n pre. 
') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = list(xlatdmn.data) msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual(' This is text\n \tfor\n pre. ', msgids[0][0]) self.assertEqual('This is text for div.', msgids[1][0]) self.assertEqual( '
THIS IS TEXT FOR DIV.
' '
 THIS IS TEXT\n \tFOR\n PRE. 
\n', result.getvalue()) # XML mode xlatdmn = self._getCollectingTranslationDomain() result = StringIO() parser = TALParser() parser.parseString( '\n' '
 This is text\n'
            ' \tfor\n barvalue. 
') program, macros = parser.getCode() self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = list(xlatdmn.data) msgids.sort() self.assertEqual(1, len(msgids)) self.assertEqual('This is text for barvalue.', msgids[0][0]) self.assertEqual( '\n' '
THIS IS TEXT  FOR BARVALUE.
\n', result.getvalue()) def test_raw_msgids_and_i18ntranslate_i18nname(self): xlatdmn = self._getCollectingTranslationDomain() result = StringIO() program, macros = self._compile( '
This is text\n \tfor\n' '
.
') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = list(xlatdmn.data) msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual(' \tRaW\n ', msgids[0][0]) self.assertEqual('This is text for ${raw}.', msgids[1][0]) self.assertEqual({'raw': '
 \tRAW\n 
'}, msgids[1][1]) self.assertEqual( u'
THIS IS TEXT FOR
 \tRAW\n 
.
\n', result.getvalue()) def test_for_handling_unicode_vars(self): # Make sure that non-ASCII Unicode is substituted correctly. # http://collector.zope.org/Zope3-dev/264 program, macros = self._compile( "
" "Foo
") self._check(program, u"
FOO \u00C0
\n") def test_for_untranslated_messageid_simple(self): program, macros = self._compile('') self._check(program, "don't translate me\n") def test_for_untranslated_messageid_i18nname(self): program, macros = self._compile( '
' '' '
') self._check(program, "
don't translate me
\n") class I18NErrorsTestCase(TestCaseBase): def _check(self, src, msg): try: self._compile(src) except I18NError: pass else: self.fail(msg) def test_id_with_replace(self): self._check('

', "expected i18n:id with tal:replace to be denied") def test_missing_values(self): self._check('

', "missing i18n:attributes value not caught") self._check('

', "missing i18n:data value not caught") self._check('

', "missing i18n:id value not caught") def test_id_with_attributes(self): self._check('''''', "expected attribute being both part of tal:attributes" + " and having a msgid in i18n:attributes to be denied") class OutputPresentationTestCase(TestCaseBase): def test_attribute_wrapping(self): # To make sure the attribute-wrapping code is invoked, we have to # include at least one TAL/METAL attribute to avoid having the start # tag optimized into a rawtext instruction. INPUT = r""" """ EXPECTED = r''' ''' "\n" self.compare(INPUT, EXPECTED) def test_unicode_content(self): INPUT = """

para

""" EXPECTED = u"""

déjà-vu

""" "\n" self.compare(INPUT, EXPECTED) def test_unicode_structure(self): INPUT = """

para

""" EXPECTED = u"""déjà-vu""" "\n" self.compare(INPUT, EXPECTED) def test_i18n_replace_number(self): INPUT = """

para

""" EXPECTED = u"""

FOO 123

""" "\n" self.compare(INPUT, EXPECTED) def test_entities(self): INPUT = ('') EXPECTED = ('&a;  
 '
                    '&a &#45 &; &#0a; <>\n') self.compare(INPUT, EXPECTED) def compare(self, INPUT, EXPECTED): program, macros = self._compile(INPUT) sio = StringIO() interp = TALInterpreter(program, {}, DummyEngine(), sio, wrap=60) interp() self.assertEqual(sio.getvalue(), EXPECTED) class InterpolateTestCase(TestCaseBase): def test_syntax_ok(self): text = "foo ${bar_0MAN} $baz_zz bee" mapping = {'bar_0MAN': 'fish', 'baz_zz': 'moo'} expected = "foo fish moo bee" self.assertEqual(interpolate(text, mapping), expected) def test_syntax_bad(self): text = "foo $_bar_man} $ ${baz bee" mapping = {'_bar_man': 'fish', 'baz': 'moo'} expected = text self.assertEqual(interpolate(text, mapping), expected) def test_missing(self): text = "foo ${bar} ${baz}" mapping = {'bar': 'fish'} expected = "foo fish ${baz}" self.assertEqual(interpolate(text, mapping), expected) def test_redundant(self): text = "foo ${bar}" mapping = {'bar': 'fish', 'baz': 'moo'} expected = "foo fish" self.assertEqual(interpolate(text, mapping), expected) def test_numeric(self): text = "foo ${bar}" mapping = {'bar': 123} expected = "foo 123" self.assertEqual(interpolate(text, mapping), expected) def test_unicode(self): text = u"foo ${bar}" mapping = {u'bar': u'baz'} expected = u"foo baz" self.assertEqual(interpolate(text, mapping), expected) def test_unicode_mixed_unknown_encoding(self): # This test assumes that sys.getdefaultencoding is ascii... text = u"foo ${bar}" mapping = {u'bar': 'd\xe9j\xe0'} expected = u"foo d\\xe9j\\xe0" self.assertEqual(interpolate(text, mapping), expected) def test_suite(): suite = unittest.makeSuite(I18NErrorsTestCase) suite.addTest(unittest.makeSuite(MacroErrorsTestCase)) suite.addTest(unittest.makeSuite(OutputPresentationTestCase)) suite.addTest(unittest.makeSuite(I18NCornerTestCase)) suite.addTest(unittest.makeSuite(InterpolateTestCase)) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite()) sys.exit(errs and 1 or 0)