1# Copyright (c) 2004 Divmod. 2# See LICENSE for details. 3 4from nevow.testutil import TestCase 5 6from nevow.flat.flatsax import parse, parseString 7from nevow.flat import flatten 8from nevow.stan import Tag, slot 9 10def norm(s): 11 return ' '.join(s.split()) 12 13class Basic(TestCase): 14 """ 15 Tests for Nevow documents which are loaded via L{xml.sax} from XHTML 16 templates. 17 """ 18 def _tagChildren(self, tag): 19 """ 20 Return a list of the children of C{tag} which are themselves L{Tag}s. 21 """ 22 return [x for x in tag.children if isinstance(x, Tag)] 23 24 25 def test_tagLocation(self): 26 """ 27 L{Tag} instances returned by L{parse} have a C{filename} attribute 28 which gives the name of the file from which they were parsed, a 29 C{lineNumber} attribute giving the line number on which the tag was 30 seen in that file, and a C{columnNumber} attribute giving the column 31 number at which the tag was seen in that file. 32 """ 33 fName = self.mktemp() 34 fObj = file(fName, 'w') 35 fObj.write( 36 '<html>\n' 37 ' <head>\n' 38 ' <title>\n' 39 ' Hello, world.\n' 40 ' </title>\n' 41 ' </head>\n' 42 ' <body>\n' 43 ' Hi.\n' 44 ' </body>\n' 45 '</html>\n') 46 fObj.close() 47 [html] = parse(file(fName)) 48 [head, body] = self._tagChildren(html) 49 [title] = self._tagChildren(head) 50 self.assertEqual(html.filename, fName) 51 self.assertEqual(html.lineNumber, 1) 52 self.assertEqual(html.columnNumber, 0) 53 self.assertEqual(head.filename, fName) 54 self.assertEqual(head.lineNumber, 2) 55 self.assertEqual(head.columnNumber, 2) 56 self.assertEqual(title.filename, fName) 57 self.assertEqual(title.lineNumber, 3) 58 self.assertEqual(title.columnNumber, 4) 59 self.assertEqual(body.filename, fName) 60 self.assertEqual(body.lineNumber, 7) 61 self.assertEqual(body.columnNumber, 2) 62 63 64 def test_attrLocation(self): 65 """ 66 I{attr} L{Tag} instances returned by L{parse} have a C{filename} 67 attribute which gives the name of the file from which they were parsed, 68 a C{lineNumber} attribute giving the line number on which the tag was 69 seen in that file, and a C{columnNumber} attribute giving the column 70 number at which the tag was seen in that file. 71 """ 72 fName = self.mktemp() 73 fObj = file(fName, 'w') 74 fObj.write( 75 '<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">\n' 76 ' <nevow:attr name="foo" />\n' 77 '</html>\n') 78 fObj.close() 79 [html] = parse(file(fName)) 80 attr = html.attributes['foo'] 81 self.assertEqual(attr.filename, fName) 82 self.assertEqual(attr.lineNumber, 2) 83 self.assertEqual(attr.columnNumber, 4) 84 85 86 def test_slotLocation(self): 87 """ 88 L{slot} instances returned by L{parse} have the same C{filename}, 89 C{lineNumber}, and C{columnNumber} attributes as L{Tag} instances do. 90 """ 91 fName = self.mktemp() 92 fObj = file(fName, 'w') 93 fObj.write( 94 '<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">\n' 95 ' <nevow:slot name="foo" />\n' 96 '</html>') 97 fObj.close() 98 [html] = parse(file(fName)) 99 [foo] = [x for x in html.children if isinstance(x, slot)] 100 self.assertEqual(foo.filename, fName) 101 self.assertEqual(foo.lineNumber, 2) 102 self.assertEqual(foo.columnNumber, 4) 103 104 105 def test_parseString(self): 106 xml = '''<html></html>''' 107 self.failUnlessEqual(xml, flatten(parseString(xml))) 108 109 def test_attrs(self): 110 xml = '''<p class="foo"></p>''' 111 self.failUnlessEqual(xml, flatten(parseString(xml))) 112 113 def test_xmlns(self): 114 xml = '''<html xmlns="http://www.w3.org/1999/xhtml"></html>''' 115 self.failUnlessEqual(xml, flatten(parseString(xml))) 116 117 def test_processingInstruction(self): 118 xml = '''<html></html>''' 119 self.failUnlessEqual(xml, flatten(parseString(xml))) 120 121 def test_doctype(self): 122 xml = ( 123 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' 124 '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' 125 '<html></html>') 126 self.failUnlessEqual(norm(xml), norm(flatten(parseString(xml)))) 127 128 def test_entities(self): 129 xml = """<p>&</p>""" 130 self.failUnlessEqual(xml, flatten(parseString(xml))) 131 132 def test_cdata(self): 133 xml = '<script type="text/javascript"><![CDATA[<abc]]></script>' 134 self.failUnlessEqual(xml, flatten(parseString(xml))) 135 136 def test_comment(self): 137 xml = '<!-- comment &£ --><html></html>' 138 self.failUnlessEqual(xml, flatten(parseString(xml))) 139 140 def test_commentWhereSpacingMatters(self): 141 """ 142 Explicitly test that spacing in comments is maintained. 143 """ 144 xml = """<head> 145<!--[if IE]> 146<style> 147div.logo { 148 margin-left: 10px; 149} 150</style> 151<![endif]--> 152</head>""" 153 self.failUnlessEqual(xml, flatten(parseString(xml))) 154 155 def test_unicodeComment(self): 156 xml = '<!-- \xc2\xa3 --><html></html>' 157 self.failUnlessEqual(xml, flatten(parseString(xml))) 158 159 def test_xmlAttr(self): 160 xml = '<html xml:lang="en"></html>' 161 self.failUnlessEqual(xml, flatten(parseString(xml))) 162 163 def test_badNamespace(self): 164 xml = '<html foo:bar="wee"><abc:p>xyz</abc:p></html>' 165 self.failUnlessEqual(xml, flatten(parseString(xml))) 166 test_badNamespace.skip = ( 167 'the standard 2.3 sax parser likes all namespaces to be defined ' 168 'so this test fails. it does pass with python-xml') 169 170 def test_switchns(self): 171 xml = ( 172 '<html xmlns="http://www.w3.org/1999/xhtml">' 173 '<p>in default namespace</p>' 174 '<foo:div xmlns:foo="http://www.w3.org/1999/xhtml">' 175 '<foo:p>in foo namespace</foo:p></foo:div></html>') 176 self.failUnlessEqual(xml, flatten(parseString(xml))) 177 178 def test_otherns(self): 179 xml = ( 180 '<html xmlns="http://www.w3.org/1999/xhtml" ' 181 'xmlns:xf="http://www.w3.org/2002/xforms"><p>' 182 'in default namespace</p><xf:input><xf:label>' 183 'in another namespace</xf:label></xf:input></html>') 184 self.failUnlessEqual(xml, flatten(parseString(xml))) 185 186 def test_invisiblens(self): 187 """ 188 Test that invisible tags do not get output with a namespace. 189 """ 190 xml = ( 191 '<p xmlns:n="http://nevow.com/ns/nevow/0.1">' 192 '<n:invisible>123</n:invisible></p>') 193 self.failUnlessEqual('<p>123</p>', flatten(parseString(xml))) 194