[Happydoc-checkins] CVS: HappyDoc3/happydoclib/docset/docset_TAL/TAL/tests utils.py,NONE,1.1 test_xm
Brought to you by:
doughellmann,
krlosaqp
From: Doug H. <dou...@us...> - 2003-01-26 19:10:49
|
Update of /cvsroot/happydoc/HappyDoc3/happydoclib/docset/docset_TAL/TAL/tests In directory sc8-pr-cvs1:/tmp/cvs-serv30698/happydoclib/docset/docset_TAL/TAL/tests Added Files: utils.py test_xmlparser.py test_talinterpreter.py test_sourcepos.py test_htmltalparser.py test_htmlparser.py test_files.py run.py __init__.py Log Message: Import the TAL package from Zope2 CVS. Refer to the LICENSE.txt file for licensing information. --- NEW FILE: utils.py --- """Helper functions for the test suite.""" import os import sys mydir = os.path.abspath(os.path.dirname(__file__)) codedir = os.path.dirname(os.path.dirname(mydir)) if codedir not in sys.path: sys.path.append(codedir) import unittest # Set skipxml to true if an XML parser could not be found. pyexpat = None skipxml = 0 try: import pyexpat except ImportError: try: # the C extension in PyXML import xml.parsers.pyexpat except ImportError: skipxml = 1 else: pyexpat = xml.parsers.pyexpat # Set oldexpat if the StartDoctypeDeclHandler and XmlDeclHandler are # not supported. The tests need to know whether the events reported # by those handlers should be expected, but need to make sure the # right thing is returned if they are. oldexpat = 0 if pyexpat is not None: p = pyexpat.ParserCreate() # Can't use hasattr() since pyexpat supports the handler # attributes in a broken way. try: p.StartDoctypeDeclHandler = None except AttributeError: oldexpat = 1 def run_suite(suite, outf=None, errf=None): if outf is None: outf = sys.stdout runner = unittest.TextTestRunner(outf) result = runner.run(suite) ## print "\n\n" ## if result.errors: ## print "Errors (unexpected exceptions):" ## map(print_error, result.errors) ## print ## if result.failures: ## print "Failures (assertion failures):" ## map(print_error, result.failures) ## print newerrs = len(result.errors) + len(result.failures) if newerrs: print "'Errors' indicate exceptions other than AssertionError." print "'Failures' indicate AssertionError" if errf is None: errf = sys.stderr errf.write("%d errors, %d failures\n" % (len(result.errors), len(result.failures))) return newerrs def print_error(info): testcase, (type, e, tb) = info --- NEW FILE: test_xmlparser.py --- #! /usr/bin/env python1.5 """Tests for XMLParser.py.""" import string import sys from TAL.tests import utils import unittest from TAL import XMLParser class EventCollector(XMLParser.XMLParser): def __init__(self): self.events = [] self.append = self.events.append XMLParser.XMLParser.__init__(self) self.parser.ordered_attributes = 1 def get_events(self): # Normalize the list of events so that buffer artefacts don't # separate runs of contiguous characters. L = [] prevtype = None for event in self.events: type = event[0] if type == prevtype == "data": L[-1] = ("data", L[-1][1] + event[1]) else: L.append(event) prevtype = type self.events = L return L # structure markup def StartElementHandler(self, tag, attrs): self.append(("starttag", tag, attrs)) def EndElementHandler(self, tag): self.append(("endtag", tag)) # all other markup def CommentHandler(self, data): self.append(("comment", data)) def handle_charref(self, data): self.append(("charref", data)) def CharacterDataHandler(self, data): self.append(("data", data)) def StartDoctypeDeclHandler(self, rootelem, publicId, systemId, subset): self.append(("doctype", rootelem, systemId, publicId, subset)) def XmlDeclHandler(self, version, encoding, standalone): self.append(("decl", version, encoding, standalone)) def ExternalEntityRefHandler(self, data): self.append(("entityref", data)) def ProcessingInstructionHandler(self, target, data): self.append(("pi", target, data)) class EventCollectorExtra(EventCollector): def handle_starttag(self, tag, attrs): EventCollector.handle_starttag(self, tag, attrs) self.append(("starttag_text", self.get_starttag_text())) class SegmentedFile: def __init__(self, parts): self.parts = list(parts) def read(self, bytes): if self.parts: s = self.parts.pop(0) else: s = '' return s class XMLParserTestCase(unittest.TestCase): def _run_check(self, source, events, collector=EventCollector): parser = collector() if isinstance(source, type([])): parser.parseStream(SegmentedFile(source)) else: parser.parseString(source) if utils.oldexpat: while events[0][0] in ('decl', 'doctype'): del events[0] self.assertEquals(parser.get_events(), events) def _run_check_extra(self, source, events): self._run_check(source, events, EventCollectorExtra) def _parse_error(self, source): def parse(source=source): parser = XMLParser.XMLParser() parser.parseString(source) self.assertRaises(XMLParser.XMLParseError, parse) def check_processing_instruction_plus(self): self._run_check("<?processing instruction?><a/>", [ ("pi", "processing", "instruction"), ("starttag", "a", []), ("endtag", "a"), ]) def _check_simple_html(self): self._run_check("""\ <?xml version='1.0' encoding='iso-8859-1'?> <!DOCTYPE html PUBLIC 'foo' 'bar'> <html>&entity;  <!--comment1a -></foo><bar><<?pi?></foo<bar comment1b--> <img src='Bar' ismap=''/>sample text <!--comment2a- -comment2b--> </html> """, [ ("decl", "1.0", "iso-8859-1", -1), ("doctype", "html", "foo", "bar", 0), ("starttag", "html", []), # ("entityref", "entity"), ("data", " \n"), ("comment", "comment1a\n-></foo><bar><<?pi?></foo<bar\ncomment1b"), ("data", "\n"), ("starttag", "img", ["src", "Bar", "ismap", ""]), ("endtag", "img"), ("data", "sample\ntext\n"), ("comment", "comment2a- -comment2b"), ("data", "\n"), ("endtag", "html"), ]) def check_bad_nesting(self): try: self._run_check("<a><b></a></b>", [ ("starttag", "a", []), ("starttag", "b", []), ("endtag", "a"), ("endtag", "b"), ]) except: e = sys.exc_info()[1] self.assert_(e.lineno == 1, "did not receive correct position information") else: self.fail("expected parse error: bad nesting") def check_attr_syntax(self): output = [ ("starttag", "a", ["b", "v", "c", "v"]), ("endtag", "a"), ] self._run_check("""<a b='v' c="v"/>""", output) self._run_check("""<a b = 'v' c = "v"/>""", output) self._run_check("""<a\nb\n=\n'v'\nc\n=\n"v"\n/>""", output) self._run_check("""<a\tb\t=\t'v'\tc\t=\t"v"\t/>""", output) def check_attr_values(self): self._run_check("""<a b='xxx\n\txxx' c="yyy\t\nyyy" d='\txyz\n'/>""", [("starttag", "a", ["b", "xxx xxx", "c", "yyy yyy", "d", " xyz "]), ("endtag", "a"), ]) self._run_check("""<a b='' c="" d=''/>""", [ ("starttag", "a", ["b", "", "c", "", "d", ""]), ("endtag", "a"), ]) def check_attr_entity_replacement(self): self._run_check("""<a b='&><"''/>""", [ ("starttag", "a", ["b", "&><\"'"]), ("endtag", "a"), ]) def check_attr_funky_names(self): self._run_check("""<a a.b='v' c:d='v' e-f='v'/>""", [ ("starttag", "a", ["a.b", "v", "c:d", "v", "e-f", "v"]), ("endtag", "a"), ]) def check_starttag_end_boundary(self): self._run_check("""<a b='<'/>""", [ ("starttag", "a", ["b", "<"]), ("endtag", "a"), ]) self._run_check("""<a b='>'/>""", [ ("starttag", "a", ["b", ">"]), ("endtag", "a"), ]) def check_buffer_artefacts(self): output = [("starttag", "a", ["b", "<"]), ("endtag", "a")] self._run_check(["<a b='<'/>"], output) self._run_check(["<a ", "b='<'/>"], output) self._run_check(["<a b", "='<'/>"], output) self._run_check(["<a b=", "'<'/>"], output) self._run_check(["<a b='<", "'/>"], output) self._run_check(["<a b='<'", "/>"], output) output = [("starttag", "a", ["b", ">"]), ("endtag", "a")] self._run_check(["<a b='>'/>"], output) self._run_check(["<a ", "b='>'/>"], output) self._run_check(["<a b", "='>'/>"], output) self._run_check(["<a b=", "'>'/>"], output) self._run_check(["<a b='>", "'/>"], output) self._run_check(["<a b='>'", "/>"], output) def check_starttag_junk_chars(self): self._parse_error("<") self._parse_error("<>") self._parse_error("</>") self._parse_error("</$>") self._parse_error("</") self._parse_error("</a") self._parse_error("</a") self._parse_error("<a<a>") self._parse_error("</a<a>") self._parse_error("<$") self._parse_error("<$>") self._parse_error("<!") self._parse_error("<a $>") self._parse_error("<a") self._parse_error("<a foo='bar'") self._parse_error("<a foo='bar") self._parse_error("<a foo='>'") self._parse_error("<a foo='>") def check_declaration_junk_chars(self): self._parse_error("<!DOCTYPE foo $ >") # Support for the Zope regression test framework: def test_suite(skipxml=utils.skipxml): suite = unittest.TestSuite() if not skipxml: suite.addTest(unittest.makeSuite(XMLParserTestCase, "check_")) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite(skipxml=0)) sys.exit(errs and 1 or 0) --- NEW FILE: test_talinterpreter.py --- #! /usr/bin/env python1.5 """Tests for TALInterpreter.""" import sys from TAL.tests import utils import unittest from StringIO import StringIO from TAL.TALDefs import METALError from TAL.HTMLTALParser import HTMLTALParser from TAL.TALInterpreter import TALInterpreter from TAL.DummyEngine import DummyEngine 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('<p metal:define-macro="M">Booh</p>') self.macro = macros['M'] self.engine = DummyEngine(macros) program, dummy = self._compile('<p metal:use-macro="M">Bah</p>') self.interpreter = TALInterpreter(program, {}, self.engine) def tearDown(self): try: self.interpreter() except METALError: pass else: self.fail("Expected METALError") def check_mode_error(self): self.macro[1] = ("mode", "duh") def check_version_error(self): self.macro[0] = ("version", "duh") class OutputPresentationTestCase(TestCaseBase): def check_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""" <html this='element' has='a' lot='of' attributes=', so' the='output' needs='to' be='line' wrapped='.' tal:define='foo nothing'> </html>""" EXPECTED = r''' <html this="element" has="a" lot="of" attributes=", so" the="output" needs="to" be="line" wrapped="."> </html>''' "\n" self.compare(INPUT, EXPECTED) def check_unicode_content(self): INPUT = """<p tal:content="python:u'déjà-vu'">para</p>""" EXPECTED = u"""<p>déjà-vu</p>""" "\n" self.compare(INPUT, EXPECTED) def check_unicode_structure(self): INPUT = """<p tal:replace="structure python:u'déjà-vu'">para</p>""" EXPECTED = u"""déjà-vu""" "\n" self.compare(INPUT, EXPECTED) def check_entities(self): INPUT = ('<img tal:define="foo nothing" ' 'alt="&a;  
 &a - &; �a; <>" />') EXPECTED = ('<img alt="&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) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(MacroErrorsTestCase, "check_")) suite.addTest(unittest.makeSuite(OutputPresentationTestCase, "check_")) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite()) sys.exit(errs and 1 or 0) --- NEW FILE: test_sourcepos.py --- #! /usr/bin/env python """Tests for TALInterpreter.""" import sys import unittest from StringIO import StringIO from TAL.HTMLTALParser import HTMLTALParser from TAL.TALInterpreter import TALInterpreter from TAL.TALGenerator import TALGenerator from TAL.DummyEngine import DummyEngine page1 = '''<html metal:use-macro="main"><body> <div metal:fill-slot="body"> page1=<span tal:replace="position:" /> </div> </body></html>''' main_template = '''<html metal:define-macro="main"><body> main_template=<span tal:replace="position:" /> <div metal:define-slot="body" /> main_template=<span tal:replace="position:" /> <div metal:use-macro="foot" /> main_template=<span tal:replace="position:" /> </body></html>''' footer = '''<div metal:define-macro="foot"> footer=<span tal:replace="position:" /> </div>''' expected = '''<html><body> main_template=main_template (2,14) <div> page1=page1 (3,6) </div> main_template=main_template (4,14) <div> footer=footer (2,7) </div> main_template=main_template (6,14) </body></html>''' class Tests(unittest.TestCase): def parse(self, eng, s, fn): gen = TALGenerator(expressionCompiler=eng, xml=0, source_file=fn) parser = HTMLTALParser(gen) parser.parseString(s) program, macros = parser.getCode() return program, macros def testSourcePositions(self): """Ensure source file and position are set correctly by TAL""" macros = {} eng = DummyEngine(macros) page1_program, page1_macros = self.parse(eng, page1, 'page1') main_template_program, main_template_macros = self.parse( eng, main_template, 'main_template') footer_program, footer_macros = self.parse(eng, footer, 'footer') macros['main'] = main_template_macros['main'] macros['foot'] = footer_macros['foot'] stream = StringIO() interp = TALInterpreter(page1_program, macros, eng, stream) interp() self.assertEqual(stream.getvalue().strip(), expected.strip(), stream.getvalue()) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(Tests)) return suite if __name__ == "__main__": unittest.main() --- NEW FILE: test_htmltalparser.py --- #! /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.0 (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 from TAL import HTMLTALParser from TAL.TALDefs import TAL_VERSION, TALError, METALError 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("""<html a='b' b="c" c=d><title>My Title</html>""", [ rawtext('<html a="b" b="c" c="d">' '<title>My Title</title></html>'), ]) def check_code_implied_list_closings(self): self._run_check("""<ul><li><p><p><li></ul>""", [ rawtext('<ul><li><p></p><p></p></li><li></li></ul>'), ]) self._run_check("""<dl><dt><dt><dd><dd><ol><li><li></ol></dl>""", [ rawtext('<dl><dt></dt><dt></dt><dd></dd>' '<dd><ol><li></li><li></li></ol></dd></dl>'), ]) def check_code_implied_table_closings(self): self._run_check("""<p>text <table><tr><th>head\t<tr><td>cell\t""" """<table><tr><td>cell \n \t \n<tr>""", [ rawtext('<p>text</p> <table><tr><th>head</th>' '</tr>\t<tr><td>cell\t<table><tr><td>cell</td>' '</tr> \n \t \n<tr></tr></table></td></tr></table>'), ]) self._run_check("""<table><tr><td>cell """ """<table><tr><td>cell </table></table>""", [ rawtext('<table><tr><td>cell <table><tr><td>cell</td></tr>' ' </table></td></tr></table>'), ]) def check_code_bad_nesting(self): def check(self=self): self._run_check("<a><b></a></b>", []) self.assertRaises(HTMLTALParser.NestingError, check) def check_code_attr_syntax(self): output = [ rawtext('<a b="v" c="v" d="v" e></a>'), ] self._run_check("""<a b='v' c="v" d=v e>""", output) self._run_check("""<a b = 'v' c = "v" d = v e>""", output) self._run_check("""<a\nb\n=\n'v'\nc\n=\n"v"\nd\n=\nv\ne>""", output) self._run_check("""<a\tb\t=\t'v'\tc\t=\t"v"\td\t=\tv\te>""", output) def check_code_attr_values(self): self._run_check( """<a b='xxx\n\txxx' c="yyy\t\nyyy" d='\txyz\n'>""", [ rawtext('<a b="xxx\n\txxx" c="yyy\t\nyyy" d="\txyz\n"></a>')]) self._run_check("""<a b='' c="">""", [ rawtext('<a b="" c=""></a>'), ]) def check_code_attr_entity_replacement(self): # we expect entities *not* to be replaced by HTLMParser! self._run_check("""<a b='&><"''>""", [ rawtext('<a b="&><"\'"></a>'), ]) self._run_check("""<a b='\"'>""", [ rawtext('<a b="""></a>'), ]) self._run_check("""<a b='&'>""", [ rawtext('<a b="&"></a>'), ]) self._run_check("""<a b='<'>""", [ rawtext('<a b="<"></a>'), ]) def check_code_attr_funky_names(self): self._run_check("""<a a.b='v' c:d=v e-f=v>""", [ rawtext('<a a.b="v" c:d="v" e-f="v"></a>'), ]) def check_code_pcdata_entityref(self): self._run_check(""" """, [ rawtext(' '), ]) def check_code_short_endtags(self): self._run_check("""<html><img/></html>""", [ rawtext('<html><img /></html>'), ]) class METALGeneratorTestCases(TestCaseBase): def check_null(self): self._run_check("", []) def check_define_macro(self): macro = self.initial_program + [ ('startTag', ('p', [('metal:define-macro', 'M', 'metal')])), rawtext('booh</p>'), ] program = [ ('setPosition', (1, 0)), ('defineMacro', ('M', macro)), ] macros = {'M': macro} self._run_check('<p metal:define-macro="M">booh</p>', program, macros) def check_use_macro(self): self._run_check('<p metal:use-macro="M">booh</p>', [ ('setPosition', (1, 0)), ('useMacro', ('M', '$M$', {}, [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])), rawtext('booh</p>')])), ]) 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</span>')])), rawtext('bar</p>'), ] program = [('setPosition', (1, 0)), ('defineMacro', ('M', macro))] macros = {'M': macro} self._run_check('<p metal:define-macro="M">foo' '<span metal:define-slot="S">spam</span>bar</p>', program, macros) def check_fill_slot(self): self._run_check('<p metal:use-macro="M">foo' '<span metal:fill-slot="S">spam</span>bar</p>', [ ('setPosition', (1, 0)), ('useMacro', ('M', '$M$', {'S': [('startTag', ('span', [('metal:fill-slot', 'S', 'metal')])), rawtext('spam</span>')]}, [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])), rawtext('foo'), ('setPosition', (1, 26)), ('fillSlot', ('S', [('startTag', ('span', [('metal:fill-slot', 'S', 'metal')])), rawtext('spam</span>')])), rawtext('bar</p>')])), ]) class TALGeneratorTestCases(TestCaseBase): def check_null(self): self._run_check("", []) def check_define_1(self): self._run_check("<p tal:define='xyzzy string:spam'></p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:define': 'xyzzy string:spam'}), ('setLocal', ('xyzzy', '$string:spam$')), ('startTag', ('p', [('tal:define', 'xyzzy string:spam', 'tal')])), ('endScope', ()), rawtext('</p>'), ]) def check_define_2(self): self._run_check("<p tal:define='local xyzzy string:spam'></p>", [ ('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('</p>'), ]) def check_define_3(self): self._run_check("<p tal:define='global xyzzy string:spam'></p>", [ ('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('</p>'), ]) def check_define_4(self): self._run_check("<p tal:define='x string:spam; y x'></p>", [ ('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('</p>'), ]) def check_define_5(self): self._run_check("<p tal:define='x string:;;;;; y x'></p>", [ ('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('</p>'), ]) def check_define_6(self): self._run_check( "<p tal:define='x string:spam; global y x; local z y'></p>", [ ('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('</p>'), ]) def check_condition(self): self._run_check( "<p><span tal:condition='python:1'><b>foo</b></span></p>", [ rawtext('<p>'), ('setPosition', (1, 3)), ('beginScope', {'tal:condition': 'python:1'}), ('condition', ('$python:1$', [('startTag', ('span', [('tal:condition', 'python:1', 'tal')])), rawtext('<b>foo</b></span>')])), ('endScope', ()), rawtext('</p>'), ]) def check_content_1(self): self._run_check("<p tal:content='string:foo'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'string:foo'}), ('startTag', ('p', [('tal:content', 'string:foo', 'tal')])), ('insertText', ('$string:foo$', [rawtext('bar')])), ('endScope', ()), rawtext('</p>'), ]) def check_content_2(self): self._run_check("<p tal:content='text string:foo'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'text string:foo'}), ('startTag', ('p', [('tal:content', 'text string:foo', 'tal')])), ('insertText', ('$string:foo$', [rawtext('bar')])), ('endScope', ()), rawtext('</p>'), ]) def check_content_3(self): self._run_check("<p tal:content='structure string:<br>'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:content': 'structure string:<br>'}), ('startTag', ('p', [('tal:content', 'structure string:<br>', 'tal')])), ('insertStructure', ('$string:<br>$', {}, [rawtext('bar')])), ('endScope', ()), rawtext('</p>'), ]) def check_replace_1(self): self._run_check("<p tal:replace='string:foo'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'string:foo'}), ('insertText', ('$string:foo$', [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')])), rawtext('bar</p>')])), ('endScope', ()), ]) def check_replace_2(self): self._run_check("<p tal:replace='text string:foo'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'text string:foo'}), ('insertText', ('$string:foo$', [('startTag', ('p', [('tal:replace', 'text string:foo', 'tal')])), rawtext('bar</p>')])), ('endScope', ()), ]) def check_replace_3(self): self._run_check("<p tal:replace='structure string:<br>'>bar</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'structure string:<br>'}), ('insertStructure', ('$string:<br>$', {}, [('startTag', ('p', [('tal:replace', 'structure string:<br>', 'tal')])), rawtext('bar</p>')])), ('endScope', ()), ]) def check_repeat(self): self._run_check("<p tal:repeat='x python:(1,2,3)'>" "<span tal:replace='x'>dummy</span></p>", [ ('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'}), ('insertText', ('$x$', [('startTag', ('span', [('tal:replace', 'x', 'tal')])), rawtext('dummy</span>')])), ('endScope', ()), rawtext('</p>')])), ('endScope', ()), ]) def check_attributes_1(self): self._run_check("<a href='foo' name='bar' tal:attributes=" "'href string:http://www.zope.org; x string:y'>" "link</a>", [ ('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), ('name', 'name="bar"'), ('tal:attributes', 'href string:http://www.zope.org; x string:y', 'tal'), ('x', None, 'insert', '$string:y$', 0)])), ('endScope', ()), rawtext('link</a>'), ]) def check_attributes_2(self): self._run_check("<p tal:replace='structure string:<img>' " "tal:attributes='src string:foo.png'>duh</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:attributes': 'src string:foo.png', 'tal:replace': 'structure string:<img>'}), ('insertStructure', ('$string:<img>$', {'src': ('$string:foo.png$', 0)}, [('startTag', ('p', [('tal:replace', 'structure string:<img>', 'tal'), ('tal:attributes', 'src string:foo.png', 'tal')])), rawtext('duh</p>')])), ('endScope', ()), ]) def check_on_error_1(self): self._run_check("<p tal:on-error='string:error' " "tal:content='notHere'>okay</p>", [ ('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('</p>')], [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:content', 'notHere', 'tal')])), ('insertText', ('$string:error$', [])), rawtext('</p>')])), ('endScope', ()), ]) def check_on_error_2(self): self._run_check("<p tal:on-error='string:error' " "tal:replace='notHere'>okay</p>", [ ('setPosition', (1, 0)), ('beginScope', {'tal:replace': 'notHere', 'tal:on-error': 'string:error'}), ('onError', ([('insertText', ('$notHere$', [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:replace', 'notHere', 'tal')])), rawtext('okay</p>')]))], [('startTag', ('p', [('tal:on-error', 'string:error', 'tal'), ('tal:replace', 'notHere', 'tal')])), ('insertText', ('$string:error$', [])), rawtext('</p>')])), ('endScope', ()), ]) def check_dup_attr(self): self._should_error("<img tal:condition='x' tal:condition='x'>") self._should_error("<img metal:define-macro='x' " "metal:define-macro='x'>", METALError) def check_tal_errors(self): self._should_error("<p tal:define='x' />") self._should_error("<p tal:repeat='x' />") self._should_error("<p tal:foobar='x' />") self._should_error("<p tal:replace='x' tal:content='x' />") self._should_error("<p tal:replace='x'>") def check_metal_errors(self): exc = METALError self._should_error(2*"<p metal:define-macro='x'>xxx</p>", exc) self._should_error("<html metal:use-macro='x'>" + 2*"<p metal:fill-slot='y' />" + "</html>", exc) self._should_error("<p metal:foobar='x' />", exc) self._should_error("<p metal:define-macro='x'>", exc) # # I18N test cases # def check_i18n_attributes(self): self._run_check("<img alt='foo' i18n:attributes='alt'>", [ ('setPosition', (1, 0)), ('beginScope', {'alt': 'foo', 'i18n:attributes': 'alt'}), ('startTag', ('img', [('alt', 'foo', 'replace', None, 1), ('i18n:attributes', 'alt', 'i18n')])), ('endScope', ()), ]) def check_i18n_translate(self): # input/test19.html self._run_check('''\ <span i18n:translate="">Replace this</span> <span i18n:translate="msgid">This is a translated string</span> <span i18n:translate="">And another translated string</span> ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': ''}), ('startTag', ('span', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextOffset', ('Replace this', 12))])), ('rawtextBeginScope', ('</span>\n', 0, (2, 0), 1, {'i18n:translate': 'msgid'})), ('startTag', ('span', [('i18n:translate', 'msgid', 'i18n')])), ('insertTranslation', ('msgid', [('rawtextColumn', ('This is a\ntranslated string', 17))])), ('rawtextBeginScope', ('</span>\n', 0, (4, 0), 1, {'i18n:translate': ''})), ('startTag', ('span', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextColumn', ('And another\ntranslated string', 17))])), ('endScope', ()), ('rawtextColumn', ('</span>\n', 0))]) def check_i18n_translate_with_nested_tal(self): self._run_check('''\ <span i18n:translate="">replaceable <p tal:replace="str:here">content</p></span> ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': ''}), ('startTag', ('span', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextOffset', ('replaceable ', 12)), ('setPosition', (1, 36)), ('beginScope', {'tal:replace': 'str:here'}), ('insertText', ('$str:here$', [('startTag', ('p', [('tal:replace', 'str:here', 'tal')])), ('rawtextOffset', ('content</p>', 11))])), ('endScope', ())])), ('endScope', ()), ('rawtextColumn', ('</span>\n', 0)) ]) def check_i18n_name(self): # input/test21.html self._run_check('''\ <span i18n:translate=""> <span tal:replace="str:Lomax" i18n:name="name" /> was born in <span tal:replace="str:Antarctica" i18n:name="country" />. </span> ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': ''}), ('startTag', ('span', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextBeginScope', ('\n ', 2, (2, 2), 0, {'i18n:name': 'name', 'tal:replace': 'str:Lomax'})), ('i18nVariable', ('name', [('startEndTag', ('span', [('tal:replace', 'str:Lomax', 'tal'), ('i18n:name', 'name', 'i18n')]))], '$str:Lomax$')), ('rawtextBeginScope', (' was born in\n ', 2, (3, 2), 1, {'i18n:name': 'country', 'tal:replace': 'str:Antarctica'})), ('i18nVariable', ('country', [('startEndTag', ('span', [('tal:replace', 'str:Antarctica', 'tal'), ('i18n:name', 'country', 'i18n')]))], '$str:Antarctica$')), ('endScope', ()), ('rawtextColumn', ('.\n', 0))])), ('endScope', ()), ('rawtextColumn', ('</span>\n', 0)) ]) def check_i18n_name_implicit_value(self): # input/test22.html self._run_check('''\ <span i18n:translate=""> <span i18n:name="name"><b>Jim</b></span> was born in <span i18n:name="country">the USA</span>. </span> ''', [ ('setPosition', (1, 0)), ('beginScope', {'i18n:translate': ''}), ('startTag', ('span', [('i18n:translate', '', 'i18n')])), ('insertTranslation', ('', [('rawtextBeginScope', ('\n ', 2, (2, 2), 0, {'i18n:name': 'name'})), ('i18nVariable', ('name', [('rawtextOffset', ('<b>Jim</b>', 10))], None)), ('rawtextBeginScope', (' was born in\n ', 2, (3, 2), 1, {'i18n:name': 'country'})), ('i18nVariable', ('country', [('rawtextOffset', ('the USA', 7))], None)), ('endScope', ()), ('rawtextColumn', ('.\n', 0))])), ('endScope', ()), ('rawtextColumn', ('</span>\n', 0)) ]) def check_i18n_context_domain(self): self._run_check("<span i18n:domain='mydomain'/>", [ ('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("<span i18n:source='en'/>", [ ('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("<span i18n:source='en' i18n:target='ru'/>", [ ('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 = ("<div metal:use-macro='M' i18n:domain='mydomain'>" "<div metal:fill-slot='S'>spam</div>" "</div>") self._run_check(text, [ ('setPosition', (1, 0)), ('useMacro', ('M', '$M$', {'S': [('startTag', ('div', [('metal:fill-slot', 'S', 'metal')])), rawtext('spam</div>')]}, [('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</div>')])), ('endScope', ()), rawtext('</div>'), ('endI18nContext', ())])), ]) def check_i18n_data(self): # input/test23.html self._run_check('''\ <span i18n:data="here/currentTime" i18n:translate="timefmt">2:32 pm</span> ''', [ ('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', ('</span>\n', 0)) ]) def check_i18n_data_with_name(self): # input/test29.html self._run_check('''\ At the tone the time will be <span i18n:data="here/currentTime" i18n:translate="timefmt" i18n:name="time">2:32 pm</span>... beep! ''', [ ('rawtextBeginScope', ('At the tone the time will be\n', 0, (2, 0), 0, {'i18n:data': 'here/currentTime', 'i18n:name': 'time', 'i18n:translate': 'timefmt'})), ('insertTranslation', ('timefmt', [('startTag', ('span', [('i18n:data', 'here/currentTime', 'i18n'), ('i18n:translate', 'timefmt', 'i18n'), ('i18n:name', 'time', 'i18n')])), ('i18nVariable', ('time', [], None))], '$here/currentTime$')), ('endScope', ()), ('rawtextColumn', ('... beep!\n', 0)) ]) def check_i18n_explicit_msgid_with_name(self): # input/test26.html self._run_check('''\ <span i18n:translate="jobnum"> Job #<span tal:replace="context/@@object_name" i18n:name="jobnum">NN</span></span> ''', [ ('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', [('startTag', ('span', [('tal:replace', 'context/@@object_name', 'tal'), ('i18n:name', 'jobnum', 'i18n')])), ('rawtextOffset', ('NN', 2)), ('rawtextOffset', ('</span>', 7))], '$context/@@object_name$')), ('endScope', ())])), ('endScope', ()), ('rawtextColumn', ('</span>\n', 0)) ]) def check_i18n_name_around_tal_content(self): # input/test28.html self._run_check('''\ <p i18n:translate="verify">Your contact email address is recorded as <span i18n:name="email"> <a href="mailto:us...@ex..." tal:content="request/submitter">us...@ho...</a></span> </p> ''', [ ('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', [('rawtextBeginScope', ('\n ', 4, (3, 4), 0, {'href': 'mailto:us...@ex...', 'tal:content': 'request/submitter'})), ('startTag', ('a', [('href', 'href="mailto:us...@ex..."'), ('tal:content', 'request/submitter', 'tal')])), ('insertText', ('$request/submitter$', [('rawtextOffset', ('us...@ho...', 13))])), ('endScope', ()), ('rawtextOffset', ('</a>', 4))], None)), ('endScope', ()), ('rawtextColumn', ('\n', 0))])), ('endScope', ()), ('rawtextColumn', ('</p>\n', 0)) ]) def check_i18n_name_with_tal_content(self): # input/test27.html self._run_check('''\ <p i18n:translate="verify">Your contact email address is recorded as <a href="mailto:us...@ex..." tal:content="request/submitter" i18n:name="email">us...@ho...</a> </p> ''', [ ('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:us...@ex...', 'i18n:name': 'email', 'tal:content': 'request/submitter'})), ('i18nVariable', ('email', [('startTag', ('a', [('href', 'href="mailto:us...@ex..."'), ('tal:content', 'request/submitter', 'tal'), ('i18n:name', 'email', 'i18n')])), ('insertText', ('$request/submitter$', [('rawtextOffset', ('us...@ho...', 13))])), ('rawtextOffset', ('</a>', 4))], None)), ('endScope', ()), ('rawtextColumn', ('\n', 0))])), ('endScope', ()), ('rawtextColumn', ('</p>\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) --- NEW FILE: test_htmlparser.py --- #! /usr/bin/env python1.5 """Tests for HTMLParser.py.""" import sys from TAL.tests import utils import unittest from TAL import HTMLParser class EventCollector(HTMLParser.HTMLParser): def __init__(self): self.events = [] self.append = self.events.append HTMLParser.HTMLParser.__init__(self) def get_events(self): # Normalize the list of events so that buffer artefacts don't # separate runs of contiguous characters. L = [] prevtype = None for event in self.events: type = event[0] if type == prevtype == "data": L[-1] = ("data", L[-1][1] + event[1]) else: L.append(event) prevtype = type self.events = L return L # structure markup def handle_starttag(self, tag, attrs): self.append(("starttag", tag, attrs)) def handle_startendtag(self, tag, attrs): self.append(("startendtag", tag, attrs)) def handle_endtag(self, tag): self.append(("endtag", tag)) # all other markup def handle_comment(self, data): self.append(("comment", data)) def handle_charref(self, data): self.append(("charref", data)) def handle_data(self, data): self.append(("data", data)) def handle_decl(self, data): self.append(("decl", data)) def handle_entityref(self, data): self.append(("entityref", data)) def handle_pi(self, data): self.append(("pi", data)) def unknown_decl(self, decl): self.append(("unknown decl", decl)) class EventCollectorExtra(EventCollector): def handle_starttag(self, tag, attrs): EventCollector.handle_starttag(self, tag, attrs) self.append(("starttag_text", self.get_starttag_text())) class TestCaseBase(unittest.TestCase): # Constant pieces of source and events prologue = "" epilogue = "" initial_events = [] final_events = [] def _run_check(self, source, events, collector=EventCollector): parser = collector() parser.feed(self.prologue) for s in source: parser.feed(s) for c in self.epilogue: parser.feed(c) parser.close() self.assert_(parser.get_events() == self.initial_events + events + self.final_events, parser.get_events()) def _run_check_extra(self, source, events): self._run_check(source, events, EventCollectorExtra) def _parse_error(self, source): def parse(source=source): parser = HTMLParser.HTMLParser() parser.feed(source) parser.close() self.assertRaises(HTMLParser.HTMLParseError, parse) class HTMLParserTestCase(TestCaseBase): def check_processing_instruction_only(self): self._run_check("<?processing instruction>", [ ("pi", "processing instruction"), ]) def check_simple_html(self): self._run_check(""" <!DOCTYPE html PUBLIC 'foo'> <HTML>&entity;  <!--comment1a -></foo><bar><<?pi?></foo<bar comment1b--> <Img sRc='Bar' isMAP>sample text “ <!--comment2a-- --comment2b--> </Html> """, [ ("data", "\n"), ("decl", "DOCTYPE html PUBLIC 'foo'"), ("data", "\n"), ("starttag", "html", []), ("entityref", "entity"), ("charref", "32"), ("data", "\n"), ("comment", "comment1a\n-></foo><bar><<?pi?></foo<bar\ncomment1b"), ("data", "\n"), ("starttag", "img", [("src", "Bar"), ("ismap", None)]), ("data", "sample\ntext\n"), ("charref", "x201C"), ("data", "\n"), ("comment", "comment2a-- --comment2b"), ("data", "\n"), ("endtag", "html"), ("data", "\n"), ]) def check_unclosed_entityref(self): self._run_check("&entityref foo", [ ("entityref", "entityref"), ("data", " foo"), ]) def check_doctype_decl(self): inside = """\ DOCTYPE html [ <!ELEMENT html - O EMPTY> <!ATTLIST html version CDATA #IMPLIED profile CDATA 'DublinCore'> <!NOTATION datatype SYSTEM 'http://xml.python.org/notations/python-module'> <!ENTITY myEntity 'internal parsed entity'> <!ENTITY anEntity SYSTEM 'http://xml.python.org/entities/something.xml'> <!ENTITY % paramEntity 'name|name|name'> %paramEntity; <!-- comment --> ]""" self._run_check("<!%s>" % inside, [ ("decl", inside), ]) def check_bad_nesting(self): # Strangely, this *is* supposed to test that overlapping # elements are allowed. HTMLParser is more geared toward # lexing the input that parsing the structure. self._run_check("<a><b></a></b>", [ ("starttag", "a", []), ("starttag", "b", []), ("endtag", "a"), ("endtag", "b"), ]) def check_bare_ampersands(self): self._run_check("this text & contains & ampersands &", [ ("data", "this text & contains & ampersands &"), ]) def check_bare_pointy_brackets(self): self._run_check("this < text > contains < bare>pointy< brackets", [ ("data", "this < text > contains < bare>pointy< brackets"), ]) def check_attr_syntax(self): output = [ ("starttag", "a", [("b", "v"), ("c", "v"), ("d", "v"), ("e", None)]) ] self._run_check("""<a b='v' c="v" d=v e>""", output) self._run_check("""<a b = 'v' c = "v" d = v e>""", output) self._run_check("""<a\nb\n=\n'v'\nc\n=\n"v"\nd\n=\nv\ne>""", output) self._run_check("""<a\tb\t=\t'v'\tc\t=\t"v"\td\t=\tv\te>""", output) def check_attr_values(self): self._run_check("""<a b='xxx\n\txxx' c="yyy\t\nyyy" d='\txyz\n'>""", [("starttag", "a", [("b", "xxx\n\txxx"), ("c", "yyy\t\nyyy"), ("d", "\txyz\n")]) ]) self._run_check("""<a b='' c="">""", [ ("starttag", "a", [("b", ""), ("c", "")]), ]) def check_attr_entity_replacement(self): self._run_check("""<a b='&><"''>""", [ ("starttag", "a", [("b", "&><\"'")]), ]) def check_attr_funky_names(self): self._run_check("""<a a.b='v' c:d=v e-f=v>""", [ ("starttag", "a", [("a.b", "v"), ("c:d", "v"), ("e-f", "v")]), ]) def check_illegal_declarations(self): self._parse_error('<!spacer type="block" height="25">') def check_starttag_end_boundary(self): self._run_check("""<a b='<'>""", [("starttag", "a", [("b", "<")])]) self._run_check("""<a b='>'>""", [("starttag", "a", [("b", ">")])]) def check_buffer_artefacts(self): output = [("starttag", "a", [("b", "<")])] self._run_check(["<a b='<'>"], output) self._run_check(["<a ", "b='<'>"], output) self._run_check(["<a b", "='<'>"], output) self._run_check(["<a b=", "'<'>"], output) self._run_check(["<a b='<", "'>"], output) self._run_check(["<a b='<'", ">"], output) output = [("starttag", "a", [("b", ">")])] self._run_check(["<a b='>'>"], output) self._run_check(["<a ", "b='>'>"], output) self._run_check(["<a b", "='>'>"], output) self._run_check(["<a b=", "'>'>"], output) self._run_check(["<a b='>", "'>"], output) self._run_check(["<a b='>'", ">"], output) def check_starttag_junk_chars(self): self._parse_error("</>") self._parse_error("</$>") self._parse_error("</") self._parse_error("</a") self._parse_error("<a<a>") self._parse_error("</a<a>") self._parse_error("<!") self._parse_error("<a $>") self._parse_error("<a") self._parse_error("<a foo='bar'") self._parse_error("<a foo='bar") self._parse_error("<a foo='>'") self._parse_error("<a foo='>") self._parse_error("<a foo=>") def check_declaration_junk_chars(self): self._parse_error("<!DOCTYPE foo $ >") def check_startendtag(self): self._run_check("<p/>", [ ("startendtag", "p", []), ]) self._run_check("<p></p>", [ ("starttag", "p", []), ("endtag", "p"), ]) self._run_check("<p><img src='foo' /></p>", [ ("starttag", "p", []), ("startendtag", "img", [("src", "foo")]), ("endtag", "p"), ]) def check_get_starttag_text(self): s = """<foo:bar \n one="1"\ttwo=2 >""" self._run_check_extra(s, [ ("starttag", "foo:bar", [("one", "1"), ("two", "2")]), ("starttag_text", s)]) def check_cdata_content(self): s = """<script> <!-- not a comment --> ¬-an-entity-ref; </script>""" self._run_check(s, [ ("starttag", "script", []), ("data", " <!-- not a comment --> ¬-an-entity-ref; "), ("endtag", "script"), ]) s = """<script> <not a='start tag'> </script>""" self._run_check(s, [ ("starttag", "script", []), ("data", " <not a='start tag'> "), ("endtag", "script"), ]) def check_enumerated_attr_type(self): s = "<!DOCTYPE doc [<!ATTLIST doc attr (a | b) >]>" self._run_check(s, [ ('decl', 'DOCTYPE doc [<!ATTLIST doc attr (a | b) >]'), ]) # Support for the Zope regression test framework: def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(HTMLParserTestCase, "check_")) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite()) sys.exit(errs and 1 or 0) --- NEW FILE: test_files.py --- #! /usr/bin/env python1.5 """Tests that run driver.py over input files comparing to output files.""" import os import sys import glob from TAL.tests import utils import unittest from TAL import runtest class FileTestCase(unittest.TestCase): def __init__(self, file, dir): self.__file = file self.__dir = dir unittest.TestCase.__init__(self) def shortDescription(self): return os.path.join("...", "TAL", "tests", "input", os.path.basename(self.__file)) def runTest(self): basename = os.path.basename(self.__file) #sys.stdout.write(basename + " ") sys.stdout.flush() if basename[:10] == 'test_metal': sys.argv = ["", "-Q", "-m", self.__file] else: sys.argv = ["", "-Q", self.__file] pwd = os.getcwd() try: try: os.chdir(self.__dir) runtest.main() finally: os.chdir(pwd) except SystemExit, what: if what.code: self.fail("output for %s didn't match" % self.__file) try: script = __file__ except NameError: script = sys.argv[0] def test_suite(): suite = unittest.TestSuite() dir = os.path.dirname(script) dir = os.path.abspath(dir) parentdir = os.path.dirname(dir) prefix = os.path.join(dir, "input", "test*.") if utils.skipxml: xmlargs = [] else: xmlargs = glob.glob(prefix + "xml") xmlargs.sort() htmlargs = glob.glob(prefix + "html") htmlargs.sort() args = xmlargs + htmlargs if not args: sys.stderr.write("Warning: no test input files found!!!\n") for arg in args: case = FileTestCase(arg, parentdir) suite.addTest(case) return suite if __name__ == "__main__": errs = utils.run_suite(test_suite()) sys.exit(errs and 1 or 0) --- NEW FILE: run.py --- #! /usr/bin/env python1.5 """Run all tests.""" import sys import utils import unittest import test_htmlparser import test_htmltalparser import test_talinterpreter import test_files import test_sourcepos def test_suite(): suite = unittest.TestSuite() suite.addTest(test_htmlparser.test_suite()) suite.addTest(test_htmltalparser.test_suite()) if not utils.skipxml: import test_xmlparser suite.addTest(test_xmlparser.test_suite()) suite.addTest(test_talinterpreter.test_suite()) suite.addTest(test_files.test_suite()) suite.addTest(test_sourcepos.test_suite()) return suite def main(): return utils.run_suite(test_suite()) if __name__ == "__main__": errs = main() sys.exit(errs and 1 or 0) --- NEW FILE: __init__.py --- """Empty file to make this directory a Python package.""" |