# Copyright (c) 2004 Divmod.
# See LICENSE for details.
from __future__ import generators
from twisted.internet import defer
from zope.interface import implements, Interface
from nevow import stan
from nevow import context
from nevow import tags
from nevow import entities
from nevow import inevow
from nevow import flat
from nevow import rend
from nevow.testutil import FakeRequest, TestCase
from nevow.flat import twist
proto = stan.Proto('hello')
class Base(TestCase):
contextFactory = context.WovenContext
def renderer(self, context, data):
return lambda context, data: ""
def setupContext(self, precompile=False, setupRequest=lambda r:r):
fr = setupRequest(FakeRequest(uri='/', currentSegments=['']))
ctx = context.RequestContext(tag=fr)
ctx.remember(fr, inevow.IRequest)
ctx.remember(None, inevow.IData)
ctx = context.WovenContext(parent=ctx, precompile=precompile)
return ctx
def render(self, tag, precompile=False, data=None, setupRequest=lambda r: r, setupContext=lambda c:c, wantDeferred=False):
ctx = self.setupContext(precompile, setupRequest)
ctx = setupContext(ctx)
if precompile:
return flat.precompile(tag, ctx)
else:
if wantDeferred:
L = []
D = twist.deferflatten(tag, ctx, L.append)
D.addCallback(lambda igresult: ''.join(L))
return D
else:
return flat.flatten(tag, ctx)
class TestSimpleSerialization(Base):
def test_serializeProto(self):
self.assertEquals(self.render(proto), '')
def test_serializeTag(self):
tag = proto(someAttribute="someValue")
self.assertEquals(self.render(tag), '')
def test_serializeChildren(self):
tag = proto(someAttribute="someValue")[
proto
]
self.assertEquals(self.render(tag), '')
def test_serializeWithData(self):
tag = proto(data=5)
self.assertEquals(self.render(tag), '')
def test_adaptRenderer(self):
## This is an implementation of the "adapt" renderer
def _(context, data):
return context.tag[
data
]
tag = proto(data=5, render=_)
self.assertEquals(self.render(tag), '5')
def test_serializeDataWithRenderer(self):
tag = proto(data=5, render=str)
self.assertEquals(self.render(tag), '5')
def test_noContextRenderer(self):
def _(data):
return data
tag = proto(data=5, render=_)
self.assertEquals(self.render(tag), '5')
tag = proto(data=5, render=lambda data: data)
self.assertEquals(self.render(tag), '5')
def test_aBunchOfChildren(self):
tag = proto[
"A Child",
5,
"A friend in need is a friend indeed"
]
self.assertEquals(self.render(tag), 'A Child5A friend in need is a friend indeed')
def test_basicPythonTypes(self):
tag = proto(data=5)[
"A string; ",
u"A unicode string; ",
5, " (An integer) ",
1.0, " (A float) ",
1L, " (A long) ",
True, " (A bool) ",
["A ", "List; "],
stan.xml(" Some xml; "),
lambda data: "A function"
]
if self.hasBools:
self.assertEquals(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) True (A bool) A List; Some xml; A function")
else:
self.assertEquals(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) 1 (A bool) A List; Some xml; A function")
def test_escaping(self):
tag = proto(foo="<>&\"'")["<>&\"'"]
self.assertEquals(self.render(tag), '<>&"\'')
class TestComplexSerialization(Base):
def test_precompileWithRenderer(self):
tag = tags.html[
tags.body[
tags.div[
tags.p["Here's a string"],
tags.p(data=5, render=str)
]
]
]
prelude, context, postlude = self.render(tag, precompile=True)
self.assertEquals(prelude, "
')
def test_precompileSlotData(self):
"""Test that tags with slotData are not precompiled out of the
stan tree.
"""
tag = tags.p[tags.slot('foo')]
tag.fillSlots('foo', 'bar')
precompiled = self.render(tag, precompile=True)
self.assertEquals(self.render(precompiled), '
')
class TestMultipleRenderWithDirective(Base):
def test_it(self):
class Cool(object):
def __init__(self):
self.counter = 0
def count(self, context, data):
self.counter += 1
return self.counter
it = Cool()
tag = tags.html(data={'counter': it.count})[
tags.invisible(data=tags.directive('counter'))[
str
]
]
precompiled = self.render(tag, precompile=True)
val = self.render(precompiled)
self.assertSubstring('1', val)
val2 = self.render(precompiled)
self.assertSubstring('2', val2)
class TestEntity(Base):
def test_it(self):
val = self.render(entities.nbsp)
self.assertEquals(val, ' ')
def test_nested(self):
val = self.render(tags.html(src=entities.quot)[entities.amp])
self.assertEquals(val, '&')
def test_xml(self):
val = self.render([entities.lt, entities.amp, entities.gt])
self.assertEquals(val, '<&>')
class TestNoneAttribute(Base):
def test_simple(self):
val = self.render(tags.html(foo=None)["Bar"])
self.assertEquals(val, "Bar")
def test_slot(self):
val = self.render(tags.html().fillSlots('bar', None)(foo=tags.slot('bar'))["Bar"])
self.assertEquals(val, "Bar")
test_slot.skip = "Attribute name flattening must happen later for this to work"
def test_deepSlot(self):
val = self.render(tags.html().fillSlots('bar', lambda c,d: None)(foo=tags.slot('bar'))["Bar"])
self.assertEquals(val, "Bar")
test_deepSlot.skip = "Attribute name flattening must happen later for this to work"
def test_deferredSlot(self):
self.render(tags.html().fillSlots('bar', defer.succeed(None))(foo=tags.slot('bar'))["Bar"],
wantDeferred=True).addCallback(
lambda val: self.assertEquals(val, "Bar"))
test_deferredSlot.skip = "Attribute name flattening must happen later for this to work"
class TestKey(Base):
def test_nested(self):
val = []
def appendKey(ctx, data):
val.append(ctx.key)
return ctx.tag
self.render(
tags.div(key="one", render=appendKey)[
tags.div(key="two", render=appendKey)[
tags.div(render=appendKey)[
tags.div(key="four", render=appendKey)]]])
self.assertEquals(val, ["one", "one.two", "one.two", "one.two.four"])
class TestDeferFlatten(Base):
def test_errorPropogation(self):
# A generator that raises an error
def gen(ctx, data):
yield 1
raise Exception('This is an exception!')
yield 2
# Hacky imports
from cStringIO import StringIO
from nevow.flat import twist
# Simple context with None IData
ctx = context.WovenContext()
ctx.remember(None, inevow.IData)
# The actual test
notquiteglobals = {}
io = StringIO()
def finished(spam):
print 'FINISHED'
def error(failure):
notquiteglobals['exception'] = failure.value
def checker(result):
if not isinstance(notquiteglobals['exception'], Exception):
self.fail('deferflatten did not errback with the correct failure')
return result
d = twist.deferflatten(gen, ctx, io.write)
d.addCallback(finished)
d.addErrback(error)
d.addBoth(checker)
return d