~divmod-dev/divmod.org/trunk

« back to all changes in this revision

Viewing changes to Nevow/nevow/test/test_flatstan.py

  • Committer: Jean-Paul Calderone
  • Date: 2014-06-29 20:33:04 UTC
  • mfrom: (2749.1.1 remove-epsilon-1325289)
  • Revision ID: exarkun@twistedmatrix.com-20140629203304-gdkmbwl1suei4m97
mergeĀ lp:~exarkun/divmod.org/remove-epsilon-1325289

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2004,2008 Divmod.
2
 
# See LICENSE for details.
3
 
 
4
 
from twisted.internet import defer
5
 
 
6
 
from zope.interface import implements, Interface
7
 
 
8
 
from nevow import stan
9
 
from nevow import context
10
 
from nevow import tags
11
 
from nevow import entities
12
 
from nevow import inevow
13
 
from nevow import flat
14
 
from nevow import rend
15
 
from nevow.testutil import FakeRequest, TestCase
16
 
 
17
 
from nevow.flat import twist
18
 
 
19
 
proto = stan.Proto('hello')
20
 
 
21
 
 
22
 
class Base(TestCase):
23
 
    contextFactory = context.WovenContext
24
 
    def renderer(self, context, data):
25
 
        return lambda context, data: ""
26
 
 
27
 
    def setupContext(self, precompile=False, setupRequest=lambda r:r):
28
 
        fr = setupRequest(FakeRequest(uri='/', currentSegments=['']))
29
 
        ctx = context.RequestContext(tag=fr)
30
 
        ctx.remember(fr, inevow.IRequest)
31
 
        ctx.remember(None, inevow.IData)
32
 
        ctx = context.WovenContext(parent=ctx, precompile=precompile)
33
 
        return ctx
34
 
 
35
 
    def render(self, tag, precompile=False, data=None, setupRequest=lambda r: r, setupContext=lambda c:c, wantDeferred=False):
36
 
        ctx = self.setupContext(precompile, setupRequest)
37
 
        ctx = setupContext(ctx)
38
 
        if precompile:
39
 
            return flat.precompile(tag, ctx)
40
 
        else:
41
 
            if wantDeferred:
42
 
                L = []
43
 
                D = twist.deferflatten(tag, ctx, L.append)
44
 
                D.addCallback(lambda igresult: ''.join(L))
45
 
                return D
46
 
            else:
47
 
                return flat.flatten(tag, ctx)
48
 
 
49
 
 
50
 
class TestSimpleSerialization(Base):
51
 
    def test_serializeProto(self):
52
 
        self.assertEquals(self.render(proto), '<hello />')
53
 
 
54
 
    def test_serializeTag(self):
55
 
        tag = proto(someAttribute="someValue")
56
 
        self.assertEquals(self.render(tag), '<hello someAttribute="someValue"></hello>')
57
 
 
58
 
    def test_serializeChildren(self):
59
 
        tag = proto(someAttribute="someValue")[
60
 
            proto
61
 
        ]
62
 
        self.assertEquals(self.render(tag), '<hello someAttribute="someValue"><hello /></hello>')
63
 
 
64
 
    def test_serializeWithData(self):
65
 
        tag = proto(data=5)
66
 
        self.assertEquals(self.render(tag), '<hello></hello>')
67
 
 
68
 
    def test_adaptRenderer(self):
69
 
        ## This is an implementation of the "adapt" renderer
70
 
        def _(context, data):
71
 
            return context.tag[
72
 
                data
73
 
            ]
74
 
        tag = proto(data=5, render=_)
75
 
        self.assertEquals(self.render(tag), '<hello>5</hello>')
76
 
 
77
 
    def test_serializeDataWithRenderer(self):
78
 
        tag = proto(data=5, render=str)
79
 
        self.assertEquals(self.render(tag), '5')
80
 
 
81
 
    def test_noContextRenderer(self):
82
 
        def _(data):
83
 
            return data
84
 
        tag = proto(data=5, render=_)
85
 
        self.assertEquals(self.render(tag), '5')
86
 
        tag = proto(data=5, render=lambda data: data)
87
 
        self.assertEquals(self.render(tag), '5')
88
 
 
89
 
    def test_aBunchOfChildren(self):
90
 
        tag = proto[
91
 
            "A Child",
92
 
            5,
93
 
            "A friend in need is a friend indeed"
94
 
        ]
95
 
        self.assertEquals(self.render(tag), '<hello>A Child5A friend in need is a friend indeed</hello>')
96
 
 
97
 
    def test_basicPythonTypes(self):
98
 
        tag = proto(data=5)[
99
 
            "A string; ",
100
 
            u"A unicode string; ",
101
 
            5, " (An integer) ",
102
 
            1.0, " (A float) ",
103
 
            1L, " (A long) ",
104
 
            True, " (A bool) ",
105
 
            ["A ", "List; "],
106
 
            stan.xml("<xml /> Some xml; "),
107
 
            lambda data: "A function"
108
 
        ]
109
 
        if self.hasBools:
110
 
            self.assertEquals(self.render(tag), "<hello>A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) True (A bool) A List; <xml /> Some xml; A function</hello>")
111
 
        else:
112
 
            self.assertEquals(self.render(tag), "<hello>A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) 1 (A bool) A List; <xml /> Some xml; A function</hello>")
113
 
 
114
 
    def test_escaping(self):
115
 
        tag = proto(foo="<>&\"'")["<>&\"'"]
116
 
        self.assertEquals(self.render(tag), '<hello foo="&lt;&gt;&amp;&quot;\'">&lt;&gt;&amp;"\'</hello>')
117
 
 
118
 
 
119
 
class TestComplexSerialization(Base):
120
 
    def test_precompileWithRenderer(self):
121
 
        tag = tags.html[
122
 
            tags.body[
123
 
                tags.div[
124
 
                    tags.p["Here's a string"],
125
 
                    tags.p(data=5, render=str)
126
 
                ]
127
 
            ]
128
 
        ]
129
 
        prelude, context, postlude = self.render(tag, precompile=True)
130
 
        self.assertEquals(prelude, "<html><body><div><p>Here's a string</p>")
131
 
        self.assertEquals(context.tag.tagName, "p")
132
 
        self.assertEquals(context.tag.data, 5)
133
 
        self.assertEquals(context.tag.render, str)
134
 
        self.assertEquals(postlude, '</div></body></html>')
135
 
 
136
 
    def test_precompileSlotData(self):
137
 
        """Test that tags with slotData are not precompiled out of the
138
 
        stan tree.
139
 
        """
140
 
        tag = tags.p[tags.slot('foo')]
141
 
        tag.fillSlots('foo', 'bar')
142
 
        precompiled = self.render(tag, precompile=True)
143
 
        self.assertEquals(self.render(precompiled), '<p>bar</p>')
144
 
 
145
 
 
146
 
    def test_precompiledSlotLocation(self):
147
 
        """
148
 
        The result of precompiling a slot preserves the location information
149
 
        associated with the slot.
150
 
        """
151
 
        filename = 'foo/bar'
152
 
        line = 123
153
 
        column = 432
154
 
        [slot] = self.render(
155
 
            tags.slot('foo', None, filename, line, column), precompile=True)
156
 
        self.assertEqual(slot.filename, filename)
157
 
        self.assertEqual(slot.lineNumber, line)
158
 
        self.assertEqual(slot.columnNumber, column)
159
 
 
160
 
 
161
 
    def makeComplex(self):
162
 
        return tags.html[
163
 
            tags.body[
164
 
                tags.table(data=5)[
165
 
                    tags.tr[
166
 
                        tags.td[
167
 
                            tags.span(render=str)
168
 
                        ],
169
 
                    ]
170
 
                ]
171
 
            ]
172
 
        ]
173
 
 
174
 
    def test_precompileTwice(self):
175
 
        def render_same(context, data):
176
 
            return context.tag
177
 
 
178
 
        doc = tags.html[
179
 
            tags.body(render=render_same, data={'foo':5})[
180
 
                tags.p["Hello"],
181
 
                tags.p(data=tags.directive('foo'))[
182
 
                    str
183
 
                ]
184
 
            ]
185
 
        ]
186
 
        result1 = self.render(doc, precompile=True)
187
 
        result2 = self.render(doc, precompile=True)
188
 
        rendered = self.render(result2)
189
 
        self.assertEquals(rendered, "<html><body><p>Hello</p><p>5</p></body></html>")
190
 
 
191
 
    def test_precompilePrecompiled(self):
192
 
        def render_same(context, data):
193
 
            return context.tag
194
 
 
195
 
        doc = tags.html[
196
 
            tags.body(render=render_same, data={'foo':5})[
197
 
                tags.p["Hello"],
198
 
                tags.p(data=tags.directive('foo'))[
199
 
                    str
200
 
                ]
201
 
            ]
202
 
        ]
203
 
        result1 = self.render(doc, precompile=True)
204
 
        result2 = self.render(result1, precompile=True)
205
 
        rendered = self.render(result2)
206
 
        self.assertEquals(rendered, "<html><body><p>Hello</p><p>5</p></body></html>")
207
 
 
208
 
    def test_precompileDoesntChangeOriginal(self):
209
 
        doc = tags.html(data="foo")[tags.p['foo'], tags.p['foo']]
210
 
 
211
 
        result = self.render(doc, precompile=True)
212
 
        rendered = self.render(result)
213
 
 
214
 
        self.assertEquals(len(doc.children), 2)
215
 
        self.assertEquals(rendered, "<html><p>foo</p><p>foo</p></html>")
216
 
 
217
 
    def test_precompileNestedDynamics(self):
218
 
        tag = self.makeComplex()
219
 
        prelude, dynamic, postlude = self.render(tag, precompile=True)
220
 
        self.assertEquals(prelude, '<html><body>')
221
 
 
222
 
        self.assertEquals(dynamic.tag.tagName, 'table')
223
 
        self.failUnless(dynamic.tag.children)
224
 
        self.assertEquals(dynamic.tag.data, 5)
225
 
 
226
 
        childPrelude, childDynamic, childPostlude = dynamic.tag.children
227
 
 
228
 
        self.assertEquals(childPrelude, '<tr><td>')
229
 
        self.assertEquals(childDynamic.tag.tagName, 'span')
230
 
        self.assertEquals(childDynamic.tag.render, str)
231
 
        self.assertEquals(childPostlude, '</td></tr>')
232
 
 
233
 
        self.assertEquals(postlude, '</body></html>')
234
 
 
235
 
    def test_precompileThenRender(self):
236
 
        tag = self.makeComplex()
237
 
        prerendered = self.render(tag, precompile=True)
238
 
        self.assertEquals(self.render(prerendered), '<html><body><table><tr><td>5</td></tr></table></body></html>')
239
 
 
240
 
    def test_precompileThenMultipleRenders(self):
241
 
        tag = self.makeComplex()
242
 
        prerendered = self.render(tag, precompile=True)
243
 
        self.assertEquals(self.render(prerendered), '<html><body><table><tr><td>5</td></tr></table></body></html>')
244
 
        self.assertEquals(self.render(prerendered), '<html><body><table><tr><td>5</td></tr></table></body></html>')
245
 
 
246
 
    def test_patterns(self):
247
 
        tag = tags.html[
248
 
            tags.body[
249
 
                tags.ol(data=["one", "two", "three"], render=rend.sequence)[
250
 
                    tags.li(pattern="item")[
251
 
                        str
252
 
                    ]
253
 
                ]
254
 
            ]
255
 
        ]
256
 
        self.assertEquals(self.render(tag), "<html><body><ol><li>one</li><li>two</li><li>three</li></ol></body></html>")
257
 
 
258
 
    def test_precompilePatternWithNoChildren(self):
259
 
        tag = tags.img(pattern='item')
260
 
        pc = flat.precompile(tag)
261
 
        self.assertEquals(pc[0].tag.children, [])
262
 
 
263
 
    def test_slots(self):
264
 
        tag = tags.html[
265
 
            tags.body[
266
 
                tags.table(data={'one': 1, 'two': 2}, render=rend.mapping)[
267
 
                    tags.tr[tags.td["Header one."], tags.td["Header two."]],
268
 
                    tags.tr[
269
 
                        tags.td["One: ", tags.slot("one")],
270
 
                        tags.td["Two: ", tags.slot("two")]
271
 
                    ]
272
 
                ]
273
 
            ]
274
 
        ]
275
 
        self.assertEquals(self.render(tag), "<html><body><table><tr><td>Header one.</td><td>Header two.</td></tr><tr><td>One: 1</td><td>Two: 2</td></tr></table></body></html>")
276
 
 
277
 
 
278
 
    def test_slotAttributeEscapingWhenPrecompiled(self):
279
 
        """
280
 
        Test that slots which represent attribute values properly quote those
281
 
        values for that context.
282
 
        """
283
 
        def render_searchResults(ctx, remoteCursor):
284
 
            ctx.fillSlots('old-query', '"meow"')
285
 
            return ctx.tag
286
 
 
287
 
        tag = tags.invisible(render=render_searchResults)[
288
 
            tags.input(value=tags.slot('old-query')),
289
 
        ]
290
 
 
291
 
        # this test passes if the precompile test is skipped.
292
 
        precompiled = self.render(tag, precompile=True)
293
 
 
294
 
        self.assertEquals(self.render(precompiled), '<input value="&quot;meow&quot;" />')
295
 
 
296
 
 
297
 
    def test_nestedpatterns(self):
298
 
        def data_table(context, data):  return [[1,2,3],[4,5,6]]
299
 
        def data_header(context, data):  return ['col1', 'col2', 'col3']
300
 
        tag = tags.html[
301
 
            tags.body[
302
 
                tags.table(data=data_table, render=rend.sequence)[
303
 
                    tags.tr(pattern='header', data=data_header, render=rend.sequence)[
304
 
                        tags.td(pattern='item')[str]
305
 
                    ],
306
 
                    tags.tr(pattern='item', render=rend.sequence)[
307
 
                        tags.td(pattern='item')[str]
308
 
                    ]
309
 
                ]
310
 
            ]
311
 
        ]
312
 
        self.assertEquals(self.render(tag), "<html><body><table><tr><td>col1</td><td>col2</td><td>col3</td></tr><tr><td>1</td><td>2</td><td>3</td></tr><tr><td>4</td><td>5</td><td>6</td></tr></table></body></html>")
313
 
 
314
 
    def test_cloning(self):
315
 
        def data_foo(context, data):  return [{'foo':'one'}, {'foo':'two'}]
316
 
 
317
 
      # tests nested lists without precompilation (precompilation flattens the lists)
318
 
        def render_test(context, data):
319
 
            return tags.ul(render=rend.sequence)[
320
 
                    tags.li(pattern='item')[
321
 
                        'foo', (((tags.invisible(data=tags.directive('foo'), render=str),),),)
322
 
                    ]
323
 
                ]
324
 
 
325
 
        # tests tags inside attributes (weird but useful)
326
 
        document = tags.html(data=data_foo)[
327
 
            tags.body[
328
 
                tags.ul(render=rend.sequence)[
329
 
                  tags.li(pattern='item')[
330
 
                    tags.a(href=('test/', tags.invisible(data=tags.directive('foo'), render=str)))['link']
331
 
                  ]
332
 
                ],
333
 
                render_test
334
 
            ]
335
 
        ]
336
 
        document=self.render(document, precompile=True)
337
 
        self.assertEquals(self.render(document), '<html><body><ul><li><a href="test/one">link</a></li><li><a href="test/two">link</a></li></ul><ul><li>fooone</li><li>footwo</li></ul></body></html>')
338
 
 
339
 
    def test_singletons(self):
340
 
        for x in ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area',
341
 
            'input', 'col', 'basefont', 'isindex', 'frame'):
342
 
            self.assertEquals(self.render(tags.Proto(x)()), '<%s />' % x)
343
 
 
344
 
    def test_nosingleton(self):
345
 
        for x in ('div', 'span', 'script', 'iframe'):
346
 
            self.assertEquals(self.render(tags.Proto(x)()), '<%(tag)s></%(tag)s>' % {'tag': x})
347
 
 
348
 
    def test_nested_data(self):
349
 
        def checkContext(ctx, data):
350
 
            self.assertEquals(data, "inner")
351
 
            self.assertEquals(ctx.locate(inevow.IData, depth=2), "outer")
352
 
            return 'Hi'
353
 
        tag = tags.html(data="outer")[tags.span(render=lambda ctx,data: ctx.tag, data="inner")[checkContext]]
354
 
        self.assertEquals(self.render(tag), "<html><span>Hi</span></html>")
355
 
 
356
 
    def test_nested_remember(self):
357
 
        class IFoo(Interface):
358
 
            pass
359
 
        class Foo(str):
360
 
            implements(IFoo)
361
 
 
362
 
        def checkContext(ctx, data):
363
 
            self.assertEquals(ctx.locate(IFoo), Foo("inner"))
364
 
            self.assertEquals(ctx.locate(IFoo, depth=2), Foo("outer"))
365
 
            return 'Hi'
366
 
        tag = tags.html(remember=Foo("outer"))[tags.span(render=lambda ctx,data: ctx.tag, remember=Foo("inner"))[checkContext]]
367
 
        self.assertEquals(self.render(tag), "<html><span>Hi</span></html>")
368
 
 
369
 
    def test_deferredRememberInRenderer(self):
370
 
        class IFoo(Interface):
371
 
            pass
372
 
        def rememberIt(ctx, data):
373
 
            ctx.remember("bar", IFoo)
374
 
            return defer.succeed(ctx.tag)
375
 
        def locateIt(ctx, data):
376
 
            return IFoo(ctx)
377
 
        tag = tags.invisible(render=rememberIt)[tags.invisible(render=locateIt)]
378
 
        self.render(tag, wantDeferred=True).addCallback(
379
 
            lambda result: self.assertEquals(result, "bar"))
380
 
 
381
 
    def test_deferredFromNestedFunc(self):
382
 
        def outer(ctx, data):
383
 
            def inner(ctx, data):
384
 
                return defer.succeed(tags.p['Hello'])
385
 
            return inner
386
 
        self.render(tags.invisible(render=outer), wantDeferred=True).addCallback(
387
 
            lambda result: self.assertEquals(result, '<p>Hello</p>'))
388
 
 
389
 
    def test_dataContextCreation(self):
390
 
        data = {'foo':'oof', 'bar':'rab'}
391
 
        doc = tags.p(data=data)[tags.slot('foo'), tags.slot('bar')]
392
 
        doc.fillSlots('foo', tags.invisible(data=tags.directive('foo'), render=str))
393
 
        doc.fillSlots('bar', lambda ctx,data: data['bar'])
394
 
        self.assertEquals(flat.flatten(doc), '<p>oofrab</p>')
395
 
 
396
 
    def test_leaky(self):
397
 
        def foo(ctx, data):
398
 
            ctx.tag.fillSlots('bar', tags.invisible(data="two"))
399
 
            return ctx.tag
400
 
 
401
 
        result = self.render(
402
 
            tags.div(render=foo, data="one")[
403
 
                tags.slot("bar"),
404
 
                tags.invisible(render=str)])
405
 
 
406
 
        self.assertEquals(result, '<div>one</div>')
407
 
 
408
 
 
409
 
class TestMultipleRenderWithDirective(Base):
410
 
    def test_it(self):
411
 
        class Cool(object):
412
 
            def __init__(self):
413
 
                self.counter = 0
414
 
 
415
 
            def count(self, context, data):
416
 
                self.counter += 1
417
 
                return self.counter
418
 
 
419
 
        it = Cool()
420
 
 
421
 
        tag = tags.html(data={'counter': it.count})[
422
 
            tags.invisible(data=tags.directive('counter'))[
423
 
                str
424
 
            ]
425
 
        ]
426
 
        precompiled = self.render(tag, precompile=True)
427
 
        val = self.render(precompiled)
428
 
        self.assertSubstring('1', val)
429
 
        val2 = self.render(precompiled)
430
 
        self.assertSubstring('2', val2)
431
 
 
432
 
 
433
 
class TestEntity(Base):
434
 
    def test_it(self):
435
 
        val = self.render(entities.nbsp)
436
 
        self.assertEquals(val, '&#160;')
437
 
 
438
 
    def test_nested(self):
439
 
        val = self.render(tags.html(src=entities.quot)[entities.amp])
440
 
        self.assertEquals(val, '<html src="&quot;">&amp;</html>')
441
 
 
442
 
    def test_xml(self):
443
 
        val = self.render([entities.lt, entities.amp, entities.gt])
444
 
        self.assertEquals(val, '&lt;&amp;&gt;')
445
 
 
446
 
 
447
 
class TestNoneAttribute(Base):
448
 
 
449
 
    def test_simple(self):
450
 
        val = self.render(tags.html(foo=None)["Bar"])
451
 
        self.assertEquals(val, "<html>Bar</html>")
452
 
 
453
 
    def test_slot(self):
454
 
        val = self.render(tags.html().fillSlots('bar', None)(foo=tags.slot('bar'))["Bar"])
455
 
        self.assertEquals(val, "<html>Bar</html>")
456
 
    test_slot.skip = "Attribute name flattening must happen later for this to work"
457
 
 
458
 
    def test_deepSlot(self):
459
 
        val = self.render(tags.html().fillSlots('bar', lambda c,d: None)(foo=tags.slot('bar'))["Bar"])
460
 
        self.assertEquals(val, "<html>Bar</html>")
461
 
    test_deepSlot.skip = "Attribute name flattening must happen later for this to work"
462
 
 
463
 
    def test_deferredSlot(self):
464
 
        self.render(tags.html().fillSlots('bar', defer.succeed(None))(foo=tags.slot('bar'))["Bar"],
465
 
                    wantDeferred=True).addCallback(
466
 
            lambda val: self.assertEquals(val, "<html>Bar</html>"))
467
 
    test_deferredSlot.skip = "Attribute name flattening must happen later for this to work"
468
 
 
469
 
 
470
 
class TestKey(Base):
471
 
    def test_nested(self):
472
 
        val = []
473
 
        def appendKey(ctx, data):
474
 
            val.append(ctx.key)
475
 
            return ctx.tag
476
 
        self.render(
477
 
            tags.div(key="one", render=appendKey)[
478
 
                tags.div(key="two", render=appendKey)[
479
 
                    tags.div(render=appendKey)[
480
 
                        tags.div(key="four", render=appendKey)]]])
481
 
        self.assertEquals(val, ["one", "one.two", "one.two", "one.two.four"])
482
 
 
483
 
 
484
 
 
485
 
class TestDeferFlatten(Base):
486
 
 
487
 
    def flatten(self, obj):
488
 
        """
489
 
        Flatten the given object using L{twist.deferflatten} and a simple context.
490
 
 
491
 
        Return the Deferred returned by L{twist.deferflatten}.
492
 
        it.
493
 
        """
494
 
        # Simple context with None IData
495
 
        ctx = context.WovenContext()
496
 
        ctx.remember(None, inevow.IData)
497
 
        return twist.deferflatten(obj, ctx, lambda bytes: None)
498
 
 
499
 
 
500
 
    def test_errorPropogation(self):
501
 
        # A generator that raises an error
502
 
        def gen(ctx, data):
503
 
            yield 1
504
 
            raise Exception('This is an exception!')
505
 
            yield 2
506
 
 
507
 
        # The actual test
508
 
        notquiteglobals = {}
509
 
        def finished(spam):
510
 
            print 'FINISHED'
511
 
        def error(failure):
512
 
            notquiteglobals['exception'] = failure.value
513
 
        def checker(result):
514
 
            if not isinstance(notquiteglobals['exception'], Exception):
515
 
                self.fail('deferflatten did not errback with the correct failure')
516
 
            return result
517
 
        d = self.flatten(gen)
518
 
        d.addCallback(finished)
519
 
        d.addErrback(error)
520
 
        d.addBoth(checker)
521
 
        return d
522
 
 
523
 
 
524
 
    def test_failurePropagation(self):
525
 
        """
526
 
        Passing a L{Deferred}, the current result of which is a L{Failure}, to
527
 
        L{twist.deferflatten} causes it to return a L{Deferred} which will be
528
 
        errbacked with that failure.  The original Deferred will also errback
529
 
        with that failure even after having been passed to
530
 
        L{twist.deferflatten}.
531
 
        """
532
 
        error = RuntimeError("dummy error")
533
 
        deferred = defer.fail(error)
534
 
 
535
 
        d = self.flatten(deferred)
536
 
        self.assertFailure(d, RuntimeError)
537
 
        d.addCallback(self.assertIdentical, error)
538
 
 
539
 
        self.assertFailure(deferred, RuntimeError)
540
 
        deferred.addCallback(self.assertIdentical, error)
541
 
 
542
 
        return defer.gatherResults([d, deferred])
543
 
 
544
 
 
545
 
    def test_resultPreserved(self):
546
 
        """
547
 
        The result of a L{Deferred} passed to L{twist.deferflatten} is the
548
 
        same before and after the call.
549
 
        """
550
 
        result = 1357
551
 
        deferred = defer.succeed(result)
552
 
        d = self.flatten(deferred)
553
 
        deferred.addCallback(self.assertIdentical, result)
554
 
        return defer.gatherResults([d, deferred])