1# Copyright (c) 2004 Divmod. 2# See LICENSE for details. 3 4 5from twisted.internet import defer 6 7from nevow import context, inevow 8from nevow import testutil 9from nevow.flat import twist 10from nevow.util import Deferred 11 12from nevow import rend, loaders, tags 13 14 15 16def deferit(data): 17 return data.d 18 19 20def deferdot(data): 21 return data.d2 22 23 24class RenderHelper(testutil.TestCase): 25 def renderIt(self): 26 req = testutil.FakeRequest() 27 self.r.renderHTTP(context.PageContext(tag=self.r, parent=context.RequestContext(tag=req))) 28 return req 29 30 31class LaterRenderTest(RenderHelper): 32 def setUp(self): 33 self.d = Deferred() 34 self.d2 = Deferred() 35 self.r = rend.Page( 36 docFactory=loaders.stan( 37 tags.html(data=self)[ 38 'Hello ', tags.invisible[tags.invisible[tags.invisible[tags.invisible[deferit]]]], 39 deferdot, 40 ] 41 ) 42 ) 43 44 def test_deferredSupport(self): 45 req = self.renderIt() 46 self.assertEquals(req.v, '<html>Hello ') 47 self.d.callback("world") 48 self.assertEquals(req.v, '<html>Hello world') 49 self.d2.callback(".") 50 self.assertEquals(req.v, '<html>Hello world.</html>') 51 52 53 def test_deferredSupport2(self): 54 req = self.renderIt() 55 self.assertEquals(req.v, '<html>Hello ') 56 self.d2.callback(".") 57 self.assertEquals(req.v, '<html>Hello ') 58 self.d.callback("world") 59 self.assertEquals(req.v, '<html>Hello world.</html>') 60 61 def test_deferredSupport3(self): 62 self.r.buffered = True 63 req = self.renderIt() 64 self.assertEquals(req.v, '') 65 self.d.callback("world") 66 self.assertEquals(req.v, '') 67 self.d2.callback(".") 68 self.assertEquals(req.v, '<html>Hello world.</html>') 69 70 def test_renderNestedDeferredCallables(self): 71 """ 72 Test flattening of a renderer which returns a Deferred which fires with 73 a renderer which returns a Deferred. 74 """ 75 def render_inner(ctx, data): 76 return defer.succeed('') 77 78 def render_outer(ctx, data): 79 return defer.succeed(render_inner) 80 81 ctx = context.WovenContext() 82 ctx.remember(None, inevow.IData) 83 84 out = [] 85 d = twist.deferflatten(render_outer, ctx, out.append) 86 def flattened(ign): 87 self.assertEquals(out, ['']) 88 d.addCallback(flattened) 89 return d 90 91 92 def test_renderNestedDeferredErrorHandling(self): 93 """ 94 Test that flattening a renderer which returns a Deferred which fires 95 with a renderer which raises an exception causes the outermost Deferred 96 to errback. 97 """ 98 class NestedException(Exception): 99 pass 100 101 def render_inner(ctx, data): 102 raise NestedException() 103 104 def render_outer(ctx, data): 105 return defer.succeed(render_inner) 106 107 ctx = context.WovenContext() 108 ctx.remember(None, inevow.IData) 109 110 out = [] 111 d = twist.deferflatten(render_outer, ctx, out.append) 112 return self.assertFailure(d, NestedException) 113 114 115class LaterDataTest(RenderHelper): 116 def data_later(self, context, data): 117 return self.d 118 119 def data_later2(self, context, data): 120 return self.d2 121 122 def setUp(self): 123 self.d = Deferred() 124 self.d2 = Deferred() 125 self.r = rend.Page(docFactory=loaders.stan( 126 tags.html(data=self.data_later)[ 127 'Hello ', str, ' and ' 128 'goodbye ',str, 129 tags.span(data=self.data_later2, render=str)])) 130 131 def test_deferredSupport(self): 132 req = self.renderIt() 133 self.assertEquals(req.v, '') 134 self.d.callback("world") 135 self.assertEquals(req.v, '<html>Hello world and goodbye world') 136 self.d2.callback(".") 137 self.assertEquals(req.v, '<html>Hello world and goodbye world.</html>') 138 139 140class SuperLaterDataTest(RenderHelper): 141 def test_reusedDeferredSupport(self): 142 """ 143 Two occurrences of a particular slot are each replaced with the 144 result of the Deferred which is used to fill that slot. 145 """ 146 doc = tags.html[ 147 tags.slot('foo'), tags.slot('foo')] 148 doc.fillSlots('foo', defer.succeed(tags.span['Foo!!!'])) 149 self.r = rend.Page(docFactory=loaders.stan(doc)) 150 req = self.renderIt() 151 self.assertEquals(req.v, '<html><span>Foo!!!</span><span>Foo!!!</span></html>') 152 153 154 def test_rendererCalledOnce(self): 155 """ 156 Make sure that if a Deferred fires with a render function that the 157 render function is called only once. 158 """ 159 calls = [] 160 def recorder(ctx, data): 161 calls.append(None) 162 return str(len(calls)) 163 doc = tags.html[tags.directive('renderer')] 164 class RendererPage(rend.Page): 165 docFactory = loaders.stan(doc) 166 def render_renderer(self, ctx, data): 167 return defer.succeed(recorder) 168 self.r = RendererPage() 169 req = self.renderIt() 170 self.assertEquals(req.v, '<html>1</html>') 171