#! /usr/bin/env python ############################################################################## # # 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 the HTMLTALParser code generator.""" import pprint import sys from TAL.tests import utils import unittest # 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 import HTMLTALParser from TAL.TALDefs import TAL_VERSION, TALError, METALError # restore warning machinery warnings.showwarning = showwarning class TestCaseBase(unittest.TestCase): prologue = "" epilogue = "" initial_program = [('version', TAL_VERSION), ('mode', 'html')] final_program = [] def _merge(self, p1, p2): if p1 and p2: op1, args1 = p1[-1] op2, args2 = p2[0] if op1.startswith('rawtext') and op2.startswith('rawtext'): return (p1[:-1] + [rawtext(args1[0] + args2[0])] + p2[1:]) return p1+p2 def _run_check(self, source, program, macros={}): parser = HTMLTALParser.HTMLTALParser() parser.parseString(self.prologue + source + self.epilogue) got_program, got_macros = parser.getCode() program = self._merge(self.initial_program, program) program = self._merge(program, self.final_program) self.assert_(got_program == program, "Program:\n" + pprint.pformat(got_program) + "\nExpected:\n" + pprint.pformat(program)) self.assert_(got_macros == macros, "Macros:\n" + pprint.pformat(got_macros) + "\nExpected:\n" + pprint.pformat(macros)) def _get_check(self, source, program=[], macros={}): parser = HTMLTALParser.HTMLTALParser() parser.parseString(source) got_program, got_macros = parser.getCode() pprint.pprint(got_program) pprint.pprint(got_macros) def _should_error(self, source, exc=TALError): def parse(self=self, source=source): parser = HTMLTALParser.HTMLTALParser() parser.parseString(self.prologue + source + self.epilogue) self.assertRaises(exc, parse) def rawtext(s): """Compile raw text to the appropriate instruction.""" if "\n" in s: return ("rawtextColumn", (s, len(s) - (s.rfind("\n") + 1))) else: return ("rawtextOffset", (s, len(s))) class HTMLTALParserTestCases(TestCaseBase): def check_code_simple_identity(self): self._run_check("""
text
head\t | ||||||||
---|---|---|---|---|---|---|---|---|
cell\t"""
"""
booh ', program, macros) def check_use_macro(self): self._run_check('booh ', [ ('setPosition', (1, 0)), ('useMacro', ('M', '$M$', {}, [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])), rawtext('booh')])), ]) def check_define_slot(self): macro = self.initial_program + [ ('startTag', ('p', [('metal:define-macro', 'M', 'metal')])), rawtext('foo'), ('setPosition', (1, 29)), ('defineSlot', ('S', [('startTag', ('span', [('metal:define-slot', 'S', 'metal')])), rawtext('spam')])), rawtext('bar'), ] program = [('setPosition', (1, 0)), ('defineMacro', ('M', macro))] macros = {'M': macro} self._run_check('foo' 'spambar ', program, macros) def check_fill_slot(self): self._run_check('foo' 'spambar ', [ ('setPosition', (1, 0)), ('useMacro', ('M', '$M$', {'S': [('startTag', ('span', [('metal:fill-slot', 'S', 'metal')])), rawtext('spam')]}, [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])), rawtext('foo'), ('setPosition', (1, 26)), ('fillSlot', ('S', [('startTag', ('span', [('metal:fill-slot', 'S', 'metal')])), rawtext('spam')])), rawtext('bar')])), ]) class TALGeneratorTestCases(TestCaseBase): def check_null(self): self._run_check("", []) def check_define_1(self): self._run_check("", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'xyzzy string:spam'}), ('setLocal', ('xyzzy', '$string:spam$')), ('startTag', ('p', [('tal:define', 'xyzzy string:spam', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_define_2(self): self._run_check("", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'local xyzzy string:spam'}), ('setLocal', ('xyzzy', '$string:spam$')), ('startTag', ('p', [('tal:define', 'local xyzzy string:spam', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_define_3(self): self._run_check("", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'global xyzzy string:spam'}), ('setGlobal', ('xyzzy', '$string:spam$')), ('startTag', ('p', [('tal:define', 'global xyzzy string:spam', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_define_4(self): self._run_check("", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'x string:spam; y x'}), ('setLocal', ('x', '$string:spam$')), ('setLocal', ('y', '$x$')), ('startTag', ('p', [('tal:define', 'x string:spam; y x', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_define_5(self): self._run_check("", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'x string:;;;;; y x'}), ('setLocal', ('x', '$string:;;$')), ('setLocal', ('y', '$x$')), ('startTag', ('p', [('tal:define', 'x string:;;;;; y x', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_define_6(self): self._run_check( "", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'x string:spam; global y x; local z y'}), ('setLocal', ('x', '$string:spam$')), ('setGlobal', ('y', '$x$')), ('setLocal', ('z', '$y$')), ('startTag', ('p', [('tal:define', 'x string:spam; global y x; local z y', 'tal')])), ('endScope', ()), rawtext(''), ]) def check_condition(self): self._run_check( "foo ", [ rawtext(''), ('setPosition', (1, 3)), ('beginScope', {'tal:condition': 'python:1'}), ('condition', ('$python:1$', [('startTag', ('span', [('tal:condition', 'python:1', 'tal')])), rawtext('foo')])), ('endScope', ()), rawtext(' '), ]) def check_content_1(self): self._run_check("bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'string:foo'}), ('startTag', ('p', [('tal:content', 'string:foo', 'tal')])), ('insertText', ('$string:foo$', [rawtext('bar')])), ('endScope', ()), rawtext(''), ]) def check_content_2(self): self._run_check("bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'text string:foo'}), ('startTag', ('p', [('tal:content', 'text string:foo', 'tal')])), ('insertText', ('$string:foo$', [rawtext('bar')])), ('endScope', ()), rawtext(''), ]) def check_content_3(self): self._run_check("bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'structure string:'}), ('startTag', ('p', [('tal:content', 'structure string: ', 'tal')])), ('insertStructure', ('$string: $', {}, [rawtext('bar')])), ('endScope', ()), rawtext(''), ]) def check_replace_1(self): self._run_check(" bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'string:foo'}), ('optTag', ('p', '', None, 0, [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')]))], [('insertText', ('$string:foo$', [rawtext('bar')]))])), ('endScope', ()), ]) def check_replace_2(self): self._run_check("bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'text string:foo'}), ('optTag', ('p', '', None, 0, [('startTag', ('p', [('tal:replace', 'text string:foo', 'tal')]))], [('insertText', ('$string:foo$', [('rawtextOffset', ('bar', 3))]))])), ('endScope', ()), ]) def check_replace_3(self): self._run_check("bar ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'structure string:'}), ('optTag', ('p', '', None, 0, [('startTag', ('p', [('tal:replace', 'structure string: ', 'tal')]))], [('insertStructure', ('$string: $', {}, [('rawtextOffset', ('bar', 3))]))])), ('endScope', ()), ]) def check_repeat(self): self._run_check(" " "dummy ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:repeat': 'x python:(1,2,3)'}), ('loop', ('x', '$python:(1,2,3)$', [('startTag', ('p', [('tal:repeat', 'x python:(1,2,3)', 'tal')])), ('setPosition', (1, 33)), ('beginScope', {'tal:replace': 'x'}), ('optTag', ('span', '', None, 0, [('startTag', ('span', [('tal:replace', 'x', 'tal')]))], [('insertText', ('$x$', [rawtext('dummy')]))])), ('endScope', ()), rawtext('')])), ('endScope', ()), ]) def check_attributes_1(self): self._run_check("" "link", [ ('setPosition', (1, 0)), ('beginScope', {'tal:attributes': 'href string:http://www.zope.org; x string:y', 'name': 'bar', 'href': 'foo'}), ('startTag', ('a', [('href', 'foo', 'replace', '$string:http://www.zope.org$', 0, None), ('name', 'name="bar"'), ('tal:attributes', 'href string:http://www.zope.org; x string:y', 'tal'), ('x', None, 'insert', '$string:y$', 0, None)])), ('endScope', ()), rawtext('link'), ]) def check_attributes_2(self): self._run_check("duh ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:attributes': 'src string:foo.png', 'tal:replace': 'structure string:okay ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'notHere', 'tal:on-error': 'string:error'}), ('onError', ([('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:content', 'notHere', 'tal')])), ('insertText', ('$notHere$', [rawtext('okay')])), rawtext('')], [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:content', 'notHere', 'tal')])), ('insertText', ('$string:error$', [])), rawtext('')])), ('endScope', ()), ]) def check_on_error_2(self): self._run_check("okay ", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'notHere', 'tal:on-error': 'string:error'}), ('onError', ([('optTag', ('p', '', None, 0, [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:replace', 'notHere', 'tal')]))], [('insertText', ('$notHere$', [('rawtextOffset', ('okay', 4))]))]))], [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:replace', 'notHere', 'tal')])), ('insertText', ('$string:error$', [])), rawtext('')])), ('endScope', ()), ]) def check_dup_attr(self): self._should_error("") for tag in HTMLTALParser.EMPTY_HTML_TAGS: self._should_error("<%s tal:content='string:foo'>" % tag) def check_metal_errors(self): exc = METALError self._should_error(2*" xxx ", exc) self._should_error("" + 2*"" + "", exc) self._should_error("", exc) self._should_error("", exc)
#
# I18N test cases
#
def check_i18n_attributes(self):
self._run_check(" content This is text for '
'.'
' ', [
('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))
])
def check_i18n_name_implicit_value(self):
# input/test22.html
self._run_check('''\
Jim was born in
the USA.
''', [
('setPosition', (1, 0)),
('beginScope', {'i18n:translate': ''}),
('startTag', ('span', [('i18n:translate', '', 'i18n')])),
('insertTranslation',
('',
[('rawtextBeginScope', ('\n ', 2, (2, 2), 0, {'i18n:name': 'name'})),
('i18nVariable',
('name',
[('startTag', ('span', [('i18n:name', 'name', 'i18n')])),
('rawtextOffset', ('Jim', 10)),
('rawtextOffset', ('', 7))],
None,
False)),
('rawtextBeginScope',
(' was born in\n ', 2, (3, 2), 1, {'i18n:name': 'country'})),
('i18nVariable',
('country',
[('startTag', ('span', [('i18n:name', 'country', 'i18n')])),
('rawtextOffset', ('the USA', 7)),
('rawtextOffset', ('', 7))],
None,
False)),
('endScope', ()),
('rawtextColumn', ('.\n', 0))])),
('endScope', ()),
('rawtextColumn', ('\n', 0))
])
def check_i18n_context_domain(self):
self._run_check("", [
('setPosition', (1, 0)),
('beginI18nContext', {'domain': 'mydomain',
'source': None, 'target': None}),
('beginScope', {'i18n:domain': 'mydomain'}),
('startEndTag', ('span', [('i18n:domain', 'mydomain', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
])
def check_i18n_context_source(self):
self._run_check("", [
('setPosition', (1, 0)),
('beginI18nContext', {'source': 'en',
'domain': 'default', 'target': None}),
('beginScope', {'i18n:source': 'en'}),
('startEndTag', ('span', [('i18n:source', 'en', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
])
def check_i18n_context_source_target(self):
self._run_check("", [
('setPosition', (1, 0)),
('beginI18nContext', {'source': 'en', 'target': 'ru',
'domain': 'default'}),
('beginScope', {'i18n:source': 'en', 'i18n:target': 'ru'}),
('startEndTag', ('span', [('i18n:source', 'en', 'i18n'),
('i18n:target', 'ru', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
])
def check_i18n_context_in_define_slot(self):
text = (""
" ")
self._run_check(text, [
('setPosition', (1, 0)),
('useMacro',
('M', '$M$',
{'S': [('startTag', ('div',
[('metal:fill-slot', 'S', 'metal')])),
rawtext('spam')]},
[('beginI18nContext', {'domain': 'mydomain',
'source': None, 'target': None}),
('beginScope',
{'i18n:domain': 'mydomain', 'metal:use-macro': 'M'}),
('startTag', ('div', [('metal:use-macro', 'M', 'metal'),
('i18n:domain', 'mydomain', 'i18n')])),
('setPosition', (1, 48)),
('fillSlot', ('S',
[('startTag',
('div', [('metal:fill-slot', 'S', 'metal')])),
rawtext('spam')])),
('endScope', ()),
rawtext(''),
('endI18nContext', ())])),
])
def check_i18n_data(self):
# input/test23.html
self._run_check('''\
2:32 pm
''', [
('setPosition', (1, 0)),
('beginScope',
{'i18n:translate': 'timefmt', 'i18n:data': 'here/currentTime'}),
('startTag',
('span',
[('i18n:data', 'here/currentTime', 'i18n'),
('i18n:translate', 'timefmt', 'i18n')])),
('insertTranslation',
('timefmt', [('rawtextOffset', ('2:32 pm', 7))], '$here/currentTime$')),
('endScope', ()),
('rawtextColumn', ('\n', 0))
])
def check_i18n_data_with_name(self):
# input/test29.html
self._run_check('''\
spam "
"At the tone the time will be
2:32 pm... beep!
''',
[('setPosition', (1, 0)),
('beginScope', {'i18n:translate': ''}),
('startTag', ('div', [('i18n:translate', '', 'i18n')])),
('insertTranslation',
('',
[('rawtextBeginScope',
('At the tone the time will be\n',
0,
(2, 0),
0,
{'i18n:data': 'here/currentTime',
'i18n:name': 'time',
'i18n:translate': 'timefmt'})),
('i18nVariable',
('time',
[('startTag',
('span',
[('i18n:data', 'here/currentTime', 'i18n'),
('i18n:translate', 'timefmt', 'i18n'),
('i18n:name', 'time', 'i18n')])),
('insertTranslation',
('timefmt',
[('rawtextOffset', ('2:32 pm', 7))],
'$here/currentTime$')),
('rawtextOffset', ('', 7))],
None,
False)),
('endScope', ()),
('rawtextOffset', ('... beep!', 9))])),
('endScope', ()),
('rawtextColumn', ('\n', 0))]
)
def check_i18n_explicit_msgid_with_name(self):
# input/test26.html
self._run_check('''\
Job #NN
''', [
('setPosition', (1, 0)),
('beginScope', {'i18n:translate': 'jobnum'}),
('startTag', ('span', [('i18n:translate', 'jobnum', 'i18n')])),
('insertTranslation',
('jobnum',
[('rawtextBeginScope',
('\n Job #',
9,
(2, 9),
0,
{'i18n:name': 'jobnum', 'tal:replace': 'context/@@object_name'})),
('i18nVariable',
('jobnum',
[('optTag',
('span',
'',
None,
0,
[('startTag',
('span',
[('tal:replace', 'context/@@object_name', 'tal'),
('i18n:name', 'jobnum', 'i18n')]))],
[('insertText',
('$context/@@object_name$',
[('rawtextOffset', ('NN', 2))]))]))],
None,
False)),
('endScope', ())])),
('endScope', ()),
('rawtextColumn', ('\n', 0))
])
def check_i18n_name_around_tal_content(self):
# input/test28.html
self._run_check('''\
Your contact email address is recorded as user@host.com ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': 'verify'}), ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])), ('insertTranslation', ('verify', [('rawtextBeginScope', ('Your contact email address is recorded as\n ', 4, (2, 4), 0, {'i18n:name': 'email'})), ('i18nVariable', ('email', [('startTag', ('span', [('i18n:name', 'email', 'i18n')])), ('rawtextBeginScope', ('\n ', 4, (3, 4), 0, {'href': 'mailto:user@example.com', 'tal:content': 'request/submitter'})), ('startTag', ('a', [('href', 'href="mailto:user@example.com"'), ('tal:content', 'request/submitter', 'tal')])), ('insertText', ('$request/submitter$', [('rawtextOffset', ('user@host.com', 13))])), ('endScope', ()), ('rawtextOffset', ('', 4)), ('rawtextOffset', ('', 7))], None, False)), ('endScope', ()), ('rawtextColumn', ('\n', 0))])), ('endScope', ()), ('rawtextColumn', ('\n', 0))]) def check_i18n_name_with_tal_content(self): # input/test27.html self._run_check('''\Your contact email address is recorded as user@host.com ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': 'verify'}), ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])), ('insertTranslation', ('verify', [('rawtextBeginScope', ('Your contact email address is recorded as\n ', 4, (2, 4), 0, {'href': 'mailto:user@example.com', 'i18n:name': 'email', 'tal:content': 'request/submitter'})), ('i18nVariable', ('email', [('startTag', ('a', [('href', 'href="mailto:user@example.com"'), ('tal:content', 'request/submitter', 'tal'), ('i18n:name', 'email', 'i18n')])), ('insertText', ('$request/submitter$', [('rawtextOffset', ('user@host.com', 13))])), ('rawtextOffset', ('', 4))], None, 0)), ('endScope', ()), ('rawtextColumn', ('\n', 0))])), ('endScope', ()), ('rawtextColumn', ('\n', 0)) ]) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(HTMLTALParserTestCases, "check_")) suite.addTest(unittest.makeSuite(METALGeneratorTestCases, "check_")) suite.addTest(unittest.makeSuite(TALGeneratorTestCases, "check_")) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite()) sys.exit(errs and 1 or 0) |