home *** CD-ROM | disk | FTP | other *** search
/ Freelog 33 / Freelog033.iso / Progr / Python-2.2.1.exe / TEST_SGMLLIB.PY < prev    next >
Encoding:
Python Source  |  2001-09-24  |  10.6 KB  |  315 lines

  1. import pprint
  2. import sgmllib
  3. import test_support
  4. import unittest
  5.  
  6.  
  7. class EventCollector(sgmllib.SGMLParser):
  8.  
  9.     def __init__(self):
  10.         self.events = []
  11.         self.append = self.events.append
  12.         sgmllib.SGMLParser.__init__(self)
  13.  
  14.     def get_events(self):
  15.         # Normalize the list of events so that buffer artefacts don't
  16.         # separate runs of contiguous characters.
  17.         L = []
  18.         prevtype = None
  19.         for event in self.events:
  20.             type = event[0]
  21.             if type == prevtype == "data":
  22.                 L[-1] = ("data", L[-1][1] + event[1])
  23.             else:
  24.                 L.append(event)
  25.             prevtype = type
  26.         self.events = L
  27.         return L
  28.  
  29.     # structure markup
  30.  
  31.     def unknown_starttag(self, tag, attrs):
  32.         self.append(("starttag", tag, attrs))
  33.  
  34.     def unknown_endtag(self, tag):
  35.         self.append(("endtag", tag))
  36.  
  37.     # all other markup
  38.  
  39.     def handle_comment(self, data):
  40.         self.append(("comment", data))
  41.  
  42.     def handle_charref(self, data):
  43.         self.append(("charref", data))
  44.  
  45.     def handle_data(self, data):
  46.         self.append(("data", data))
  47.  
  48.     def handle_decl(self, decl):
  49.         self.append(("decl", decl))
  50.  
  51.     def handle_entityref(self, data):
  52.         self.append(("entityref", data))
  53.  
  54.     def handle_pi(self, data):
  55.         self.append(("pi", data))
  56.  
  57.     def unknown_decl(self, decl):
  58.         self.append(("unknown decl", decl))
  59.  
  60.  
  61. class CDATAEventCollector(EventCollector):
  62.     def start_cdata(self, attrs):
  63.         self.append(("starttag", "cdata", attrs))
  64.         self.setliteral()
  65.  
  66.  
  67. class SGMLParserTestCase(unittest.TestCase):
  68.  
  69.     collector = EventCollector
  70.  
  71.     def get_events(self, source):
  72.         parser = self.collector()
  73.         try:
  74.             for s in source:
  75.                 parser.feed(s)
  76.             parser.close()
  77.         except:
  78.             #self.events = parser.events
  79.             raise
  80.         return parser.get_events()
  81.  
  82.     def check_events(self, source, expected_events):
  83.         try:
  84.             events = self.get_events(source)
  85.         except:
  86.             import sys
  87.             #print >>sys.stderr, pprint.pformat(self.events)
  88.             raise
  89.         if events != expected_events:
  90.             self.fail("received events did not match expected events\n"
  91.                       "Expected:\n" + pprint.pformat(expected_events) +
  92.                       "\nReceived:\n" + pprint.pformat(events))
  93.  
  94.     def check_parse_error(self, source):
  95.         parser = EventCollector()
  96.         try:
  97.             parser.feed(source)
  98.             parser.close()
  99.         except sgmllib.SGMLParseError:
  100.             pass
  101.         else:
  102.             self.fail("expected SGMLParseError for %r\nReceived:\n%s"
  103.                       % (source, pprint.pformat(parser.get_events())))
  104.  
  105.     def test_doctype_decl_internal(self):
  106.         inside = """\
  107. DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01//EN'
  108.              SYSTEM 'http://www.w3.org/TR/html401/strict.dtd' [
  109.   <!ELEMENT html - O EMPTY>
  110.   <!ATTLIST html
  111.       version CDATA #IMPLIED
  112.       profile CDATA 'DublinCore'>
  113.   <!NOTATION datatype SYSTEM 'http://xml.python.org/notations/python-module'>
  114.   <!ENTITY myEntity 'internal parsed entity'>
  115.   <!ENTITY anEntity SYSTEM 'http://xml.python.org/entities/something.xml'>
  116.   <!ENTITY % paramEntity 'name|name|name'>
  117.   %paramEntity;
  118.   <!-- comment -->
  119. ]"""
  120.         self.check_events(["<!%s>" % inside], [
  121.             ("decl", inside),
  122.             ])
  123.  
  124.     def test_doctype_decl_external(self):
  125.         inside = "DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01//EN'"
  126.         self.check_events("<!%s>" % inside, [
  127.             ("decl", inside),
  128.             ])
  129.  
  130.     def test_underscore_in_attrname(self):
  131.         # SF bug #436621
  132.         """Make sure attribute names with underscores are accepted"""
  133.         self.check_events("<a has_under _under>", [
  134.             ("starttag", "a", [("has_under", "has_under"),
  135.                                ("_under", "_under")]),
  136.             ])
  137.  
  138.     def test_underscore_in_tagname(self):
  139.         # SF bug #436621
  140.         """Make sure tag names with underscores are accepted"""
  141.         self.check_events("<has_under></has_under>", [
  142.             ("starttag", "has_under", []),
  143.             ("endtag", "has_under"),
  144.             ])
  145.  
  146.     def test_quotes_in_unquoted_attrs(self):
  147.         # SF bug #436621
  148.         """Be sure quotes in unquoted attributes are made part of the value"""
  149.         self.check_events("<a href=foo'bar\"baz>", [
  150.             ("starttag", "a", [("href", "foo'bar\"baz")]),
  151.             ])
  152.  
  153.     def test_xhtml_empty_tag(self):
  154.         """Handling of XHTML-style empty start tags"""
  155.         self.check_events("<br />text<i></i>", [
  156.             ("starttag", "br", []),
  157.             ("data", "text"),
  158.             ("starttag", "i", []),
  159.             ("endtag", "i"),
  160.             ])
  161.  
  162.     def test_processing_instruction_only(self):
  163.         self.check_events("<?processing instruction>", [
  164.             ("pi", "processing instruction"),
  165.             ])
  166.  
  167.     def test_bad_nesting(self):
  168.         self.check_events("<a><b></a></b>", [
  169.             ("starttag", "a", []),
  170.             ("starttag", "b", []),
  171.             ("endtag", "a"),
  172.             ("endtag", "b"),
  173.             ])
  174.  
  175.     def test_bare_ampersands(self):
  176.         self.check_events("this text & contains & ampersands &", [
  177.             ("data", "this text & contains & ampersands &"),
  178.             ])
  179.  
  180.     def test_bare_pointy_brackets(self):
  181.         self.check_events("this < text > contains < bare>pointy< brackets", [
  182.             ("data", "this < text > contains < bare>pointy< brackets"),
  183.             ])
  184.  
  185.     def test_attr_syntax(self):
  186.         output = [
  187.           ("starttag", "a", [("b", "v"), ("c", "v"), ("d", "v"), ("e", "e")])
  188.           ]
  189.         self.check_events("""<a b='v' c="v" d=v e>""", output)
  190.         self.check_events("""<a  b = 'v' c = "v" d = v e>""", output)
  191.         self.check_events("""<a\nb\n=\n'v'\nc\n=\n"v"\nd\n=\nv\ne>""", output)
  192.         self.check_events("""<a\tb\t=\t'v'\tc\t=\t"v"\td\t=\tv\te>""", output)
  193.  
  194.     def test_attr_values(self):
  195.         self.check_events("""<a b='xxx\n\txxx' c="yyy\t\nyyy" d='\txyz\n'>""",
  196.                         [("starttag", "a", [("b", "xxx\n\txxx"),
  197.                                             ("c", "yyy\t\nyyy"),
  198.                                             ("d", "\txyz\n")])
  199.                          ])
  200.         self.check_events("""<a b='' c="">""", [
  201.             ("starttag", "a", [("b", ""), ("c", "")]),
  202.             ])
  203.  
  204.     def test_attr_funky_names(self):
  205.         self.check_events("""<a a.b='v' c:d=v e-f=v>""", [
  206.             ("starttag", "a", [("a.b", "v"), ("c:d", "v"), ("e-f", "v")]),
  207.             ])
  208.  
  209.     def test_illegal_declarations(self):
  210.         s = 'abc<!spacer type="block" height="25">def'
  211.         self.check_events(s, [
  212.             ("data", "abc"),
  213.             ("unknown decl", 'spacer type="block" height="25"'),
  214.             ("data", "def"),
  215.             ])
  216.  
  217.     def test_weird_starttags(self):
  218.         self.check_events("<a<a>", [
  219.             ("starttag", "a", []),
  220.             ("starttag", "a", []),
  221.             ])
  222.         self.check_events("</a<a>", [
  223.             ("endtag", "a"),
  224.             ("starttag", "a", []),
  225.             ])
  226.  
  227.     def test_declaration_junk_chars(self):
  228.         self.check_parse_error("<!DOCTYPE foo $ >")
  229.  
  230.     def test_get_starttag_text(self):
  231.         s = """<foobar   \n   one="1"\ttwo=2   >"""
  232.         self.check_events(s, [
  233.             ("starttag", "foobar", [("one", "1"), ("two", "2")]),
  234.             ])
  235.  
  236.     def test_cdata_content(self):
  237.         s = ("<cdata> <!-- not a comment --> ¬-an-entity-ref; </cdata>"
  238.              "<notcdata> <!-- comment --> </notcdata>")
  239.         self.collector = CDATAEventCollector
  240.         self.check_events(s, [
  241.             ("starttag", "cdata", []),
  242.             ("data", " <!-- not a comment --> ¬-an-entity-ref; "),
  243.             ("endtag", "cdata"),
  244.             ("starttag", "notcdata", []),
  245.             ("data", " "),
  246.             ("comment", " comment "),
  247.             ("data", " "),
  248.             ("endtag", "notcdata"),
  249.             ])
  250.         s = """<cdata> <not a='start tag'> </cdata>"""
  251.         self.check_events(s, [
  252.             ("starttag", "cdata", []),
  253.             ("data", " <not a='start tag'> "),
  254.             ("endtag", "cdata"),
  255.             ])
  256.  
  257.     def test_illegal_declarations(self):
  258.         s = 'abc<!spacer type="block" height="25">def'
  259.         self.check_events(s, [
  260.             ("data", "abc"),
  261.             ("unknown decl", 'spacer type="block" height="25"'),
  262.             ("data", "def"),
  263.             ])
  264.  
  265.     # XXX These tests have been disabled by prefixing their names with
  266.     # an underscore.  The first two exercise outstanding bugs in the
  267.     # sgmllib module, and the third exhibits questionable behavior
  268.     # that needs to be carefully considered before changing it.
  269.  
  270.     def _test_starttag_end_boundary(self):
  271.         self.check_events("""<a b='<'>""", [("starttag", "a", [("b", "<")])])
  272.         self.check_events("""<a b='>'>""", [("starttag", "a", [("b", ">")])])
  273.  
  274.     def _test_buffer_artefacts(self):
  275.         output = [("starttag", "a", [("b", "<")])]
  276.         self.check_events(["<a b='<'>"], output)
  277.         self.check_events(["<a ", "b='<'>"], output)
  278.         self.check_events(["<a b", "='<'>"], output)
  279.         self.check_events(["<a b=", "'<'>"], output)
  280.         self.check_events(["<a b='<", "'>"], output)
  281.         self.check_events(["<a b='<'", ">"], output)
  282.  
  283.         output = [("starttag", "a", [("b", ">")])]
  284.         self.check_events(["<a b='>'>"], output)
  285.         self.check_events(["<a ", "b='>'>"], output)
  286.         self.check_events(["<a b", "='>'>"], output)
  287.         self.check_events(["<a b=", "'>'>"], output)
  288.         self.check_events(["<a b='>", "'>"], output)
  289.         self.check_events(["<a b='>'", ">"], output)
  290.  
  291.     def _test_starttag_junk_chars(self):
  292.         self.check_parse_error("<")
  293.         self.check_parse_error("<>")
  294.         self.check_parse_error("</$>")
  295.         self.check_parse_error("</")
  296.         self.check_parse_error("</a")
  297.         self.check_parse_error("<$")
  298.         self.check_parse_error("<$>")
  299.         self.check_parse_error("<!")
  300.         self.check_parse_error("<a $>")
  301.         self.check_parse_error("<a")
  302.         self.check_parse_error("<a foo='bar'")
  303.         self.check_parse_error("<a foo='bar")
  304.         self.check_parse_error("<a foo='>'")
  305.         self.check_parse_error("<a foo='>")
  306.         self.check_parse_error("<a foo=>")
  307.  
  308.  
  309. def test_main():
  310.     test_support.run_unittest(SGMLParserTestCase)
  311.  
  312.  
  313. if __name__ == "__main__":
  314.     test_main()
  315.