1# Copyright (c) 2004-2009 Divmod. 2# See LICENSE for details. 3 4import os 5 6from twisted.trial import unittest, util 7 8from nevow import context 9from nevow import flat 10from nevow.flat.flatstan import _PrecompiledSlot 11from nevow import loaders 12from nevow import tags as t 13 14class TestDocFactories(unittest.TestCase): 15 16 def _preprocessorTest(self, docFactory): 17 def preprocessor(uncompiled): 18 self.assertEquals(len(uncompiled), 1) 19 uncompiled = uncompiled[0] 20 self.assertEquals(uncompiled.tagName, 'div') 21 self.assertEquals(len(uncompiled.children), 2) 22 self.assertEquals(uncompiled.children[0].tagName, 'span') 23 self.assertEquals(uncompiled.children[0].children, ['Hello']) 24 self.assertEquals(uncompiled.children[1].tagName, 'span') 25 self.assertEquals(uncompiled.children[1].children, ['world']) 26 return t.div['goodbye.'] 27 doc = docFactory.load(preprocessors=[preprocessor]) 28 self.assertEquals(doc, ['<div>goodbye.</div>']) 29 30 31 def test_stanPreprocessors(self): 32 """ 33 Test that the stan loader properly passes uncompiled documents to 34 preprocessors it is given. 35 """ 36 factory = loaders.stan( 37 t.div[t.span['Hello'], t.span['world']]) 38 return self._preprocessorTest(factory) 39 40 41 def test_stan(self): 42 doc = t.ul(id='nav')[t.li['one'], t.li['two'], t.li['three']] 43 df = loaders.stan(doc) 44 self.assertEquals(df.load()[0], '<ul id="nav"><li>one</li><li>two</li><li>three</li></ul>') 45 46 47 def test_stanPrecompiled(self): 48 """ 49 Test that a stan loader works with precompiled documents. 50 51 (This behavior will probably be deprecated soon, but we need to test 52 that it works right until we remove it.) 53 """ 54 doc = flat.precompile(t.ul(id='nav')[t.li['one'], t.li['two'], t.slot('three')]) 55 df = loaders.stan(doc) 56 loaded = df.load() 57 self.assertEqual(loaded[0], '<ul id="nav"><li>one</li><li>two</li>') 58 self.failUnless(isinstance(loaded[1], _PrecompiledSlot)) 59 self.assertEqual(loaded[1].name, 'three') 60 self.assertEqual(loaded[2], '</ul>') 61 62 63 def test_htmlstr(self): 64 doc = '<ul id="nav"><li>a</li><li>b</li><li>c</li></ul>' 65 df = loaders.htmlstr(doc) 66 self.assertEquals(df.load()[0], doc) 67 test_htmlstr.suppress = [ 68 util.suppress(message= 69 r"\[v0.8\] htmlstr is deprecated because it's buggy. " 70 "Please start using xmlfile and/or xmlstr.")] 71 72 73 def test_htmlfile(self): 74 doc = '<ul id="nav"><li>a</li><li>b</li><li>c</li></ul>' 75 temp = self.mktemp() 76 f = file(temp, 'w') 77 f.write(doc) 78 f.close() 79 df = loaders.htmlfile(temp) 80 self.assertEquals(df.load()[0], doc) 81 test_htmlfile.suppress = [ 82 util.suppress(message= 83 r"\[v0.8\] htmlfile is deprecated because it's buggy. " 84 "Please start using xmlfile and/or xmlstr.")] 85 86 87 def test_htmlfile_slots(self): 88 doc = '<nevow:slot name="foo">Hi there</nevow:slot>' 89 temp = self.mktemp() 90 f = file(temp, 'w') 91 f.write(doc) 92 f.close() 93 df = loaders.htmlfile(temp) 94 self.assertEquals(df.load()[0].children, ['Hi there']) 95 test_htmlfile_slots.suppress = [ 96 util.suppress(message= 97 r"\[v0.8\] htmlfile is deprecated because it's buggy. " 98 "Please start using xmlfile and/or xmlstr.")] 99 100 101 def test_xmlstr(self): 102 doc = '<ul id="nav"><li>a</li><li>b</li><li>c</li></ul>' 103 df = loaders.xmlstr(doc) 104 self.assertEquals(df.load()[0], doc) 105 106 107 def test_xmlstrPreprocessors(self): 108 """ 109 Test that the xmlstr loader properly passes uncompiled documents to 110 preprocessors it is given. 111 """ 112 factory = loaders.xmlstr( 113 '<div><span>Hello</span><span>world</span></div>') 114 return self._preprocessorTest(factory) 115 116 117 def test_xmlfile(self): 118 doc = '<ul id="nav"><li>a</li><li>b</li><li>c</li></ul>' 119 temp = self.mktemp() 120 f = file(temp, 'w') 121 f.write(doc) 122 f.close() 123 df = loaders.xmlfile(temp) 124 self.assertEquals(df.load()[0], doc) 125 126 127 def test_xmlfilePreprocessors(self): 128 """ 129 Test that the xmlstr loader properly passes uncompiled documents to 130 preprocessors it is given. 131 """ 132 xmlFile = self.mktemp() 133 f = file(xmlFile, 'w') 134 f.write('<div><span>Hello</span><span>world</span></div>') 135 f.close() 136 factory = loaders.xmlfile(xmlFile) 137 return self._preprocessorTest(factory) 138 139 140 def test_patterned(self): 141 """Test fetching a specific part (a pattern) of the document. 142 """ 143 doc = t.div[t.p[t.span(pattern='inner')['something']]] 144 df = loaders.stan(doc, pattern='inner') 145 self.assertEquals(df.load()[0].tagName, 'span') 146 self.assertEquals(df.load()[0].children[0], 'something') 147 148 149 def test_ignoreDocType(self): 150 doc = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html><body><p>Hello.</p></body></html>''' 151 df = loaders.xmlstr(doc, ignoreDocType=True) 152 self.assertEquals(flat.flatten(df), '<html><body><p>Hello.</p></body></html>') 153 154 def test_ignoreComment(self): 155 doc = '<!-- skip this --><p>Hello.</p>' 156 df = loaders.xmlstr(doc, ignoreComment=True) 157 self.assertEquals(flat.flatten(df), '<p>Hello.</p>') 158 159 160class TestDocFactoriesCache(unittest.TestCase): 161 162 doc = ''' 163 <div> 164 <p nevow:pattern="1">one</p> 165 <p nevow:pattern="2">two</p> 166 </div> 167 ''' 168 169 nsdoc = ''' 170 <div xmlns:nevow="http://nevow.com/ns/nevow/0.1"> 171 <p nevow:pattern="1">one</p> 172 <p nevow:pattern="2">two</p> 173 </div> 174 ''' 175 176 stan = t.div[t.p(pattern='1')['one'],t.p(pattern='2')['two']] 177 178 def test_stan(self): 179 180 loader = loaders.stan(self.stan) 181 self.assertEquals( id(loader.load()), id(loader.load()) ) 182 183 loader = loaders.stan(self.stan, pattern='1') 184 self.assertEquals( id(loader.load()), id(loader.load()) ) 185 186 l1 = loaders.stan(self.stan, pattern='1') 187 l2 = loaders.stan(self.stan, pattern='1') 188 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 189 190 l1 = loaders.stan(self.stan, pattern='1') 191 l2 = loaders.stan(self.stan, pattern='2') 192 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 193 194 195 def test_htmlstr(self): 196 loader = loaders.htmlstr(self.doc) 197 self.assertEquals( id(loader.load()), id(loader.load()) ) 198 199 loader = loaders.htmlstr(self.doc, pattern='1') 200 self.assertEquals( id(loader.load()), id(loader.load()) ) 201 202 l1 = loaders.htmlstr(self.doc, pattern='1') 203 l2 = loaders.htmlstr(self.doc, pattern='1') 204 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 205 206 l1 = loaders.htmlstr(self.doc, pattern='1') 207 l2 = loaders.htmlstr(self.doc, pattern='2') 208 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 209 test_htmlstr.suppress = [ 210 util.suppress(message= 211 r"\[v0.8\] htmlstr is deprecated because it's buggy. " 212 "Please start using xmlfile and/or xmlstr.")] 213 214 215 def test_htmlfile(self): 216 temp = self.mktemp() 217 f = file(temp, 'w') 218 f.write(self.doc) 219 f.close() 220 221 loader = loaders.htmlfile(temp) 222 self.assertEquals( id(loader.load()), id(loader.load()) ) 223 224 l1 = loaders.htmlfile(temp, pattern='1') 225 l2 = loaders.htmlfile(temp, pattern='1') 226 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 227 228 l1 = loaders.htmlfile(temp, pattern='1') 229 l2 = loaders.htmlfile(temp, pattern='2') 230 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 231 test_htmlfile.suppress = [ 232 util.suppress(message= 233 r"\[v0.8\] htmlfile is deprecated because it's buggy. " 234 "Please start using xmlfile and/or xmlstr.")] 235 236 237 def test_htmlfileReload(self): 238 temp = self.mktemp() 239 f = file(temp, 'w') 240 f.write(self.doc) 241 f.close() 242 243 loader = loaders.htmlfile(temp) 244 r = loader.load() 245 self.assertEquals(id(r), id(loader.load())) 246 os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) 247 self.assertNotEqual(id(r), id(loader.load())) 248 test_htmlfileReload.suppress = [ 249 util.suppress(message= 250 r"\[v0.8\] htmlfile is deprecated because it's buggy. " 251 "Please start using xmlfile and/or xmlstr.")] 252 253 254 255 def test_xmlstr(self): 256 257 loader = loaders.xmlstr(self.nsdoc) 258 self.assertEquals( id(loader.load()), id(loader.load()) ) 259 260 loader = loaders.xmlstr(self.nsdoc, pattern='1') 261 self.assertEquals( id(loader.load()), id(loader.load()) ) 262 263 l1 = loaders.xmlstr(self.nsdoc, pattern='1') 264 l2 = loaders.xmlstr(self.nsdoc, pattern='1') 265 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 266 267 l1 = loaders.xmlstr(self.nsdoc, pattern='1') 268 l2 = loaders.xmlstr(self.nsdoc, pattern='2') 269 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 270 271 272 def test_xmlSlotDefault(self): 273 """ 274 An I{nevow:slot} tag in an XML template may have a I{default} 275 attribute specifying a value for the slot if it is not otherwise 276 given one. 277 """ 278 slotsdoc = ''' 279 <div xmlns:nevow="http://nevow.com/ns/nevow/0.1"> 280 <nevow:slot name="1" /> 281 <nevow:slot name="2" default="3" /> 282 </div> 283 ''' 284 loader = loaders.xmlstr(slotsdoc) 285 loaded = loader.load() 286 self.assertEquals(loaded[1].default, None) 287 self.assertEquals(loaded[3].default, "3") 288 289 290 def test_xmlfile(self): 291 292 temp = self.mktemp() 293 f = file(temp, 'w') 294 f.write(self.nsdoc) 295 f.close() 296 297 loader = loaders.xmlfile(temp) 298 self.assertEquals( id(loader.load()), id(loader.load()) ) 299 300 loader = loaders.xmlfile(temp, pattern='1') 301 self.assertEquals( id(loader.load()), id(loader.load()) ) 302 303 l1 = loaders.xmlfile(temp, pattern='1') 304 l2 = loaders.xmlfile(temp, pattern='1') 305 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 306 307 l1 = loaders.xmlfile(temp, pattern='1') 308 l2 = loaders.xmlfile(temp, pattern='2') 309 self.assertNotEqual( id(l1.load()), id(l2.load()) ) 310 311 def test_xmlfileReload(self): 312 313 temp = self.mktemp() 314 f = file(temp, 'w') 315 f.write(self.nsdoc) 316 f.close() 317 318 loader = loaders.xmlfile(temp) 319 r = loader.load() 320 self.assertEquals(id(r), id(loader.load())) 321 os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) 322 self.assertNotEqual(id(r), id(loader.load())) 323 324 def test_reloadAfterPrecompile(self): 325 """ 326 """ 327 # Get a filename 328 temp = self.mktemp() 329 330 # Write some content 331 f = file(temp, 'w') 332 f.write('<p>foo</p>') 333 f.close() 334 335 # Precompile the doc 336 ctx = context.WovenContext() 337 doc = loaders.htmlfile(temp) 338 pc = flat.precompile(flat.flatten(doc), ctx) 339 340 before = ''.join(flat.serialize(pc, ctx)) 341 342 343 # Write the file with different content and make sure the 344 # timestamp changes 345 f = file(temp, 'w') 346 f.write('<p>bar</p>') 347 f.close() 348 os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) 349 350 after = ''.join(flat.serialize(pc, ctx)) 351 352 self.assertIn('foo', before) 353 self.assertIn('bar', after) 354 self.failIfEqual(before, after) 355 test_reloadAfterPrecompile.todo = \ 356 'Fix so that disk templates are reloaded even after a precompile. ' \ 357 'Probably just a matter of making the DocSerializer really lazy' 358 359 360class TestContext(unittest.TestCase): 361 """Check that each of the standard loaders supports load with and without a 362 context. 363 """ 364 365 def test_stan(self): 366 doc = t.p['hello'] 367 self._withAndWithout(loaders.stan(doc)) 368 369 def test_xmlstr(self): 370 doc = '<p>hello</p>' 371 self._withAndWithout(loaders.xmlstr(doc)) 372 373 def test_xmlfile(self): 374 temp = self.mktemp() 375 f = file(temp, 'w') 376 f.write('<p>hello</p>') 377 f.close() 378 self._withAndWithout(loaders.xmlfile(temp)) 379 380 def test_htmlstr(self): 381 doc = '<p>hello</p>' 382 self._withAndWithout(loaders.htmlstr(doc)) 383 test_htmlstr.suppress = [ 384 util.suppress(message= 385 r"\[v0.8\] htmlstr is deprecated because it's buggy. " 386 "Please start using xmlfile and/or xmlstr.")] 387 388 def test_htmlfile(self): 389 temp = self.mktemp() 390 f = file(temp, 'w') 391 f.write('<p>hello</p>') 392 f.close() 393 self._withAndWithout(loaders.htmlfile(temp)) 394 test_htmlfile.suppress = [ 395 util.suppress(message= 396 r"\[v0.8\] htmlfile is deprecated because it's buggy. " 397 "Please start using xmlfile and/or xmlstr.")] 398 399 def _withAndWithout(self, loader): 400 ctx = context.WovenContext() 401 self.assertEquals(loader.load(), ['<p>hello</p>']) 402 self.assertEquals(loader.load(ctx), ['<p>hello</p>']) 403 404 405class TestParsing(unittest.TestCase): 406 407 def test_missingSpace(self): 408 doc = '<p xmlns:nevow="http://nevow.com/ns/nevow/0.1"><nevow:slot name="foo"/> <nevow:slot name="foo"/></p>' 409 ## This used to say htmlstr, and this test failed because microdom ignores whitespace; 410 ## This test passes fine using xmlstr. I am not going to fix this because microdom is too 411 ## hard to fix. If you need this, switch to xmlstr. 412 result = loaders.xmlstr(doc).load() 413 # There should be a space between the two slots 414 self.assertEquals(result[2], ' ') 415