# -*- 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$ """ import os import sys import unittest from StringIO import StringIO from zope.tal.taldefs import METALError, I18NError, TAL_VERSION from zope.tal.htmltalparser import HTMLTALParser from zope.tal.talparser import TALParser from zope.tal.talinterpreter import TALInterpreter from zope.tal.dummyengine import DummyEngine from zope.tal.dummyengine import MultipleDomainsDummyEngine from zope.tal.dummyengine import DummyTranslationDomain from zope.tal.tests import utils # BBB 2005/10/10 -- MessageIDs are to be removed for Zope 3.3 import zope.deprecation zope.deprecation.__show__.off() from zope.i18nmessageid import MessageID, Message zope.deprecation.__show__.on() 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 MacroFunkyErrorTest(TestCaseBase): def test_div_in_p_using_macro(self): dummy, macros = self._compile('

Booh

') engine = DummyEngine(macros) program, dummy = self._compile( '

foo

') interpreter = TALInterpreter(program, {}, engine) output = interpreter() self.assertEqual(output, '

foo

') class MacroExtendTestCase(TestCaseBase): def setUp(self): s = self._read(('input', 'pnome_template.pt')) self.pnome_program, pnome_macros = self._compile(s) s = self._read(('input', 'acme_template.pt')) self.acme_program, acme_macros = self._compile(s) s = self._read(('input', 'document_list.pt')) self.doclist_program, doclist_macros = self._compile(s) macros = { 'pnome_macros_page': pnome_macros['page'], 'acme_macros_page': acme_macros['page'], } self.engine = DummyEngine(macros) def _read(self, path): dir = os.path.dirname(__file__) fn = os.path.join(dir, *path) f = open(fn) data = f.read() f.close() return data def test_preview_acme_template(self): # An ACME designer is previewing the ACME design. For the # purposes of this use case, extending a macro should act the # same as using a macro. result = StringIO() interpreter = TALInterpreter( self.acme_program, {}, self.engine, stream=result) interpreter() actual = result.getvalue().strip() expected = self._read(('output', 'acme_template.html')).strip() self.assertEqual(actual, expected) def test_preview_acme_template_source(self): # Render METAL attributes in acme_template result = StringIO() interpreter = TALInterpreter( self.acme_program, {}, self.engine, stream=result, tal=False) interpreter() actual = result.getvalue().strip() expected = self._read(('output', 'acme_template_source.html')).strip() self.assertEqual(actual, expected) class I18NCornerTestCaseBase(TestCaseBase): def factory(self, msgid, default, mapping={}): raise NotImplementedError("abstract method") def setUp(self): self.engine = DummyEngine() # Make sure we'll translate the msgid not its unicode representation self.engine.setLocal('foo', self.factory('FoOvAlUe${empty}', 'default', {'empty': ''})) self.engine.setLocal('bar', 'BaRvAlUe') 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_explicit_messageid(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') 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', TAL_VERSION), ('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() #GChapelle: #I have the feeling the i18n:translate with the i18n:name is wrong # #program, macros = self._compile( # '
This is text for ' # '.
') 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(1, len(msgids)) self.assertEqual('This is text for ${bar_name}.', msgids[0][0]) self.assertEqual({'bar_name': 'BaRvAlUe'}, msgids[0][1]) self.assertEqual( '
THIS IS TEXT FOR BaRvAlUe.
\n', result.getvalue()) def test_for_correct_msgids_translate_name(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('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_i18ntranslate_i18nname_and_attributes(self): # Test for Issue 301: Bug with i18n:name and i18n:translate # on the same element self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '

' 'Some static text and a link text.

') 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('Some static text and a ${link}.', msgids[0][0]) self.assertEqual({'link': 'LINK TEXT'}, msgids[0][1]) self.assertEqual('link text', msgids[1][0]) self.assertEqual( '

SOME STATIC TEXT AND A LINK TEXT.

\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' '
 \tbar\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(' \tbar\n ', msgids[0][0]) self.assertEqual('This is text for ${bar}.', msgids[1][0]) self.assertEqual({'bar': '
 \tBAR\n 
'}, msgids[1][1]) self.assertEqual( u'
THIS IS TEXT FOR
 \tBAR\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") class I18NCornerTestCaseMessageID(I18NCornerTestCaseBase): def factory(self, msgid, default=None, mapping={}, domain=None): m = MessageID(msgid, default=default) m.mapping = mapping return m class UnusedExplicitDomainTestCase(I18NCornerTestCaseMessageID): def factory(self, msgid, default=None, mapping={}, domain=None): m = MessageID(msgid, default=default, domain=domain) m.mapping = mapping return m def setUp(self): # MultipleDomainsDummyEngine is a Engine # where default domain transforms to uppercase self.engine = MultipleDomainsDummyEngine() self.engine.setLocal('foo', self.factory('FoOvAlUe${empty}', 'default', {'empty': ''})) self.engine.setLocal('bar', 'BaRvAlUe') self.engine.setLocal('baz', self.factory('BaZvAlUe', 'default', {})) # Message ids with different domains self.engine.setLocal('toupper', self.factory('ToUpper', 'default', {})) self.engine.setLocal('tolower', self.factory('ToLower', 'default', {}, domain='lower')) def test_multiple_domains(self): program, macros = self._compile( '
') self._check(program, '
TOUPPER
\n') program, macros = self._compile( '
') self._check(program, '
tolower
\n') program, macros = self._compile( '
') self._check(program, '
TOUPPER
\n') program, macros = self._compile( '
') self._check(program, '
tolower
\n') program, macros = self._compile( '
') self._check(program, '
TOUPPER
\n') program, macros = self._compile( '
') self._check(program, '
tolower
\n') def test_unused_explicit_domain(self): #a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine #is a domain that transforms to lowercase self.engine.setLocal('othertolower', self.factory('OtherToLower', 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine', {}, domain='lower')) program, macros = self._compile( '
') self._check(program, '
othertolower
\n') #takes domain into account for strings program, macros = self._compile( '
') self._check(program, '
tolower
\n') #but not for messageids program, macros = self._compile( '
') self._check(program, '
BAZVALUE
\n') class I18NCornerTestCaseMessage(I18NCornerTestCaseBase): def factory(self, msgid, default=None, mapping={}): return Message(msgid, default=default, mapping=mapping) class ScriptTestCase(TestCaseBase): def setUp(self): self.engine = DummyEngine() 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(self): program, macros = self._compile( '

print "hello"

') self._check(program, '

hello\n

\n') def test_script_and_tal_block(self): program, macros = self._compile( '\n' ' global x\n' ' x = 1\n' '\n' '') self._check(program, '\n1\n') self.assertEqual(self.engine.codeGlobals['x'], 1) def test_script_and_tal_block_having_inside_print(self): program, macros = self._compile( '\n' ' print "hello"' '') self._check(program, 'hello\n\n') def test_script_and_omittag(self): program, macros = self._compile( '

\n' ' print "hello"' '

') self._check(program, 'hello\n\n') def test_script_and_inside_tags(self): program, macros = self._compile( '

\n' ' print "hello"' '

') self._check(program, 'hello\n\n') def test_script_and_inside_tags_with_tal(self): program, macros = self._compile( '

') self._check(program, 'hello\n\n') def test_html_script(self): program, macros = self._compile( '') self._check(program, 'Hello world!\n') def test_html_script_and_javascript(self): program, macros = self._compile( '') self._check(program, '