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>&amp;</p>"""
130        self.failUnlessEqual(xml, flatten(parseString(xml)))
131
132    def test_cdata(self):
133        xml = '<script type="text/javascript"><![CDATA[&lt;abc]]></script>'
134        self.failUnlessEqual(xml, flatten(parseString(xml)))
135
136    def test_comment(self):
137        xml = '<!-- comment &amp;&pound; --><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