# -*- 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 68333 2006-05-29 10:34:19Z philikon $ """ import sys import unittest from StringIO import StringIO # BBB 2005/05/01 -- to be changed after 12 months # ignore deprecation warnings on import for now import warnings showwarning = warnings.showwarning warnings.showwarning = lambda *a, **k: None # this old import should remain here until the TAL package is # completely removed, so that API backward compatibility is properly # tested 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 # restore warning machinery warnings.showwarning = showwarning 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.6'), ('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 test_for_correct_msgids(self): self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '
This is text for ' '.
') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = self.engine.translationDomain.getMsgids('default') 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 self.engine.translationDomain.clearMsgids() 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 = self.engine.translationDomain.getMsgids('default') 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 self.engine.translationDomain.clearMsgids() 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 = self.engine.translationDomain.getMsgids('default') 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): self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '
This is text\n \tfor\n' '
.
') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() msgids = self.engine.translationDomain.getMsgids('default') 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) # this test just tests sick behaviour, we'll disable it #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)