Exemple #1
0
    def test_(self):
        """
        Verify that C{_associateWithImplementation} is called on the
        message passed to L{ExistingMessageMIMEStorer.__init__} with
        the correct values after parsing is finished.

        WHITEBOX.
        """
        mime = PartMaker('text/plain', 'Hello, world.')

        class Message:
            def _associateWithImplementation(self, impl, source):
                self.impl = impl
                self.source = source

        store = Store()
        deliveryDir = self.mktemp()
        os.makedirs(deliveryDir)
        fObj = AtomicFile(
            filepath.FilePath(deliveryDir).child('tmp.eml').path,
            filepath.FilePath(deliveryDir).child('message.eml'))
        source = u'test://blarg'
        message = Message()
        storer = ExistingMessageMIMEStorer(store, fObj, source, message)
        part = storer.feedStringNow(mime.make())
        self.assertIdentical(message.impl, part)
        self.assertEqual(message.source, source)
        self.assertEqual(message.recipient, u'<No Recipient>')
        self.assertEqual(message.subject, u'<No Subject>')
    def test_(self):
        """
        Verify that C{_associateWithImplementation} is called on the
        message passed to L{ExistingMessageMIMEStorer.__init__} with
        the correct values after parsing is finished.

        WHITEBOX.
        """
        mime = PartMaker('text/plain', 'Hello, world.')
        class Message:
            def _associateWithImplementation(self, impl, source):
                self.impl = impl
                self.source = source
        store = Store()
        deliveryDir = self.mktemp()
        os.makedirs(deliveryDir)
        fObj = AtomicFile(
            filepath.FilePath(deliveryDir).child('tmp.eml').path,
            filepath.FilePath(deliveryDir).child('message.eml'))
        source = u'test://blarg'
        message = Message()
        storer = ExistingMessageMIMEStorer(store, fObj, source, message)
        part = storer.feedStringNow(mime.make())
        self.assertIdentical(message.impl, part)
        self.assertEqual(message.source, source)
        self.assertEqual(message.recipient, u'<No Recipient>')
        self.assertEqual(message.subject, u'<No Subject>')
Exemple #3
0
 def test_messageSourceReplacesIllegalChars(self):
     """
     Test that L{xquotient.exmess.MessageSourceFragment} renders the source
     of a message with XML-illegal characters replaced
     """
     self.setUpMailStuff()
     m = self.createMIMEReceiver().feedStringNow(
         PartMaker('text/html', '\x00 \x01 hi').make()).message
     f = MessageSourceFragment(m)
     self.assertEqual(f.source(None, None),
                      PartMaker('text/html', '0x0 0x1 hi').make() + '\n')
Exemple #4
0
class PrintableMessageResourceTestCase(TestCase, MIMEReceiverMixin):
    """
    Tests for L{xquotient.exmess.PrintableMessageResource}
    """
    boringMessage = PartMaker('text/plain', 'plain').make()

    def setUp(self):
        self.setUpMailStuff()
        self.boringMessageItem = self.createMIMEReceiver().feedStringNow(
            self.boringMessage).message
        self.resource = PrintableMessageResource(self.boringMessageItem)

    def test_noActions(self):
        """
        Test that L{PrintableMessageResource.renderHTTP} returns something
        wrapping an L{ActionlessMessageDetail}
        """
        res = self.resource.renderHTTP(None)
        self.failUnless(isinstance(res.fragment, ActionlessMessageDetail))

    def test_username(self):
        """
        Verify that the L{GenericNavigationAthenaPage} returned from
        L{PrintableMessageResource.renderHTTP} has the C{username} attribute
        set to the right value.
        """
        res = self.resource.renderHTTP(None)
        self.assertEqual(res.username, u'*****@*****.**')
Exemple #5
0
class MessageBodyFragmentTestCase(TestCase, MIMEReceiverMixin):
    """
    Test L{xquotient.exmess.MessageBodyFragment}
    """

    altInsideMixed = PartMaker(
        'multipart/mixed', 'mixed',
        PartMaker('multipart/alternative', 'alt',
                  PartMaker('text/plain', 'plain'),
                  PartMaker('text/html', '<html />')),
        PartMaker('text/plain', 'plain')).make()

    def test_alternateMIMETypesAltMixed(self):
        """
        Test that C{text/html} is the only alternate MIME type returned by
        L{xquotient.exmess.MessageBodyFragment.getAlternateMIMETypes} for
        L{altInsideMixed}
        """
        self.setUpMailStuff()
        m = self.createMIMEReceiver().feedStringNow(
            self.altInsideMixed).message
        messageBody = MessageBodyFragment(m, 'text/plain')

        self.assertEqual(list(messageBody.getAlternateMIMETypes()),
                         ['text/html'])

    def test_getAlternatePartBodyAltMixed(self):
        """
        Test that the parts returned from
        L{xquotient.exmess.MessageBodyFragment.getAlternatePartBody} are of
        the type C{text/html} and C{text/plain}, in that order, when asked for
        C{text/html} part bodies from L{altInsideMixed}
        """
        self.setUpMailStuff()
        m = self.createMIMEReceiver().feedStringNow(
            self.altInsideMixed).message
        messageBody = MessageBodyFragment(m, 'text/plain')
        messageBody = messageBody.getAlternatePartBody('text/html')

        self.assertEqual(list(p.type for p in messageBody.parts),
                         ['text/html', 'text/plain'])

    mixed = PartMaker('multipart/mixed', 'mixed',
                      PartMaker('text/plain', 'plain'),
                      PartMaker('text/html', 'html')).make()

    def test_getAlternateMIMETypesMixed(self):
        """
        Test that there are no alternate MIME types returned by
        L{xquotient.exmess.MessageBodyFragment.getAlternateMIMETypes} for
        L{mixed}
        """
        self.setUpMailStuff()
        m = self.createMIMEReceiver().feedStringNow(self.mixed).message
        messageBody = MessageBodyFragment(m, 'text/plain')

        self.assertEqual(list(messageBody.getAlternateMIMETypes()), [])
Exemple #6
0
    def test_unknownMultipartTypeAsMixed(self):
        """
        Test that unknown multipart mime types are rendered with 'multipart/mixed'
        content types (with their original content).

          Any "multipart" subtypes that an implementation does not recognize
          must be treated as being of subtype "mixed".

        RFC 2046, Section 5.1.3
        """
        content = PartMaker('multipart/appledouble', 'appledouble',
                            PartMaker('text/applefile', 'applefile'),
                            PartMaker('image/jpeg', 'jpeg')).make()
        part = self.setUpMailStuff().feedStringNow(content)
        walkedPart = part.walkMessage('image/jpeg').next()
        self.assertEquals(walkedPart.type, 'multipart/mixed')
        self.assertEquals(walkedPart.part, part)
    def test_createMessageWithMultipartAttachment(self):
        """
        Test L{xquotient.mimebakery.createMessage} when there is
        a multipart attachment
        """
        fileItem = self.cabinet.createFileItem(
            u'a multipart', u'multipart/mixed',
            PartMaker('multipart/mixed', 'mixed',
                      PartMaker('text/plain', 'text/plain #1'),
                      PartMaker('text/plain', 'text/plain #2')).make())
        msg = self._createMessageWithFiles((fileItem, ))
        multipart = list(msg.impl.walk())[-3]
        self.assertEquals(multipart.getContentType(), 'multipart/mixed')
        self._assertFilenameParamEquals(multipart, 'a multipart')

        (_, textPlain1, textPlain2) = multipart.walk()
        self.assertEquals(textPlain1.getContentType(), 'text/plain')
        self.assertEquals(textPlain1.getBody(), 'text/plain #1\n')

        self.assertEquals(textPlain2.getContentType(), 'text/plain')
        self.assertEquals(textPlain2.getBody(), 'text/plain #2\n')
Exemple #8
0
    def test_unknownTypeAsOctetStream(self):
        """
        Test that unknown non-multipart mime types are rendered as
        'application/octet-stream'.

        See RFC 2046, Section 4 for more details.
        """
        content = PartMaker('image/applefile', 'applefile').make()
        part = self.setUpMailStuff().feedStringNow(content)
        walkedPart = part.walkMessage(None).next()
        self.assertEquals(walkedPart.type, 'application/octet-stream')
        self.assertEquals(walkedPart.part, part)
    def test_createMessageWithMessageAttachment(self):
        """
        Test L{xquotient.mimebakery.createMessage} when there is
        an attachment of type message/rfc822
        """
        fileItem = self.cabinet.createFileItem(
            u'a message', u'message/rfc822',
            PartMaker('text/plain', 'some text/plain').make())
        msg = self._createMessageWithFiles((fileItem, ))
        rfc822part = list(msg.impl.walk())[-2]
        self.assertEquals(rfc822part.getContentType(), 'message/rfc822')
        self._assertFilenameParamEquals(rfc822part, 'a message')

        (_, textPlainPart) = rfc822part.walk()
        self.assertEquals(textPlainPart.getContentType(), 'text/plain')
        self.assertEquals(textPlainPart.getBody(), 'some text/plain\n')
Exemple #10
0
class MessageDataTestCase(unittest.TestCase, PersistenceMixin):
    """
    Test the L{IMessageData} implementation provided by L{Part}.
    """

    fromDisplay = u'\N{LATIN CAPITAL LETTER A WITH GRAVE}lice'
    fromEmail = u'*****@*****.**'
    fromAddress = u'%s <%s>' % (fromDisplay, fromEmail)

    senderDisplay = u'B\N{LATIN SMALL LETTER O WITH GRAVE}b'
    senderEmail = u'*****@*****.**'
    senderAddress = u'%s <%s>' % (senderDisplay, senderEmail)

    replyToDisplay = u'C\N{LATIN SMALL LETTER A WITH GRAVE}rol'
    replyToEmail = u'*****@*****.**'
    replyToAddress = u'%s <%s>' % (replyToDisplay, replyToEmail)

    toDisplay = u'Dav\N{LATIN SMALL LETTER A WITH GRAVE}'
    toEmail = u'*****@*****.**'
    toAddress = u'%s <%s>' % (toDisplay, toEmail)

    ccDisplay = u'\N{LATIN CAPITAL LETTER E WITH GRAVE}ve'
    ccEmail = u'*****@*****.**'
    ccAddress = u'%s <%s>' % (ccDisplay, ccEmail)

    bccDisplay = u'Is\N{LATIN SMALL LETTER A WITH GRAVE}ac'
    bccEmail = u'*****@*****.**'
    bccAddress = u'%s <%s>' % (bccDisplay, bccEmail)

    resentFromDisplay = u'Iv\N{LATIN SMALL LETTER A WITH GRAVE}n'
    resentFromEmail = u'*****@*****.**'
    resentFromAddress = u'%s <%s>' % (resentFromDisplay, resentFromEmail)

    resentToDisplay = u'M\N{LATIN SMALL LETTER A WITH GRAVE}llory'
    resentToEmail = u'*****@*****.**'
    resentToAddress = u'%s <%s>' % (resentToDisplay, resentToEmail)

    def setUp(self):
        self.headers = {
            'from': self._header('From', self.fromAddress),
            'sender': self._header('Sender', self.senderAddress),
            'reply-to': self._header('Reply-To', self.replyToAddress),
            'cc': self._header('Cc', self.ccAddress),
            'to': self._header('To', self.toAddress),
            'bcc': self._header('Bcc', self.bccAddress),
            'resent-from': self._header('Resent-From', self.resentFromAddress),
            'resent-to': self._header('Resent-To', self.resentToAddress)
        }

    def _header(self, name, value):
        return (name + ': ' + email.quopriMIME.header_encode(value) +
                '\n').encode('ascii')

    def _relationTest(self, headers, relation, email, display):
        msgSource = msg(relatedAddressesMessage % headers)

        def checkRelatedAddresses(part):
            for (kind, addr) in part.relatedAddresses():
                if kind == relation:
                    self.assertEqual(addr.email, email)
                    self.assertEqual(addr.display, display)
                    break
            else:
                self.fail("Did not find %r" % (relation, ))

        self._messageTest(msgSource, checkRelatedAddresses)

    def test_senderAddressWithFrom(self):
        """
        Test that L{Part.relatedAddresses} yields a sender address taken from
        the C{From} header of a message, if that header is present.
        """
        self._relationTest(self.headers, SENDER_RELATION, self.fromEmail,
                           self.fromDisplay)

    def test_senderAddressWithSender(self):
        """
        Test that L{Part.relatedAddresses} yields a sender address taken from
        the C{Sender} header of a message, if that header is present and the
        C{From} header is not.
        """
        self.headers['from'] = ''
        self._relationTest(self.headers, SENDER_RELATION, self.senderEmail,
                           self.senderDisplay)

    def test_senderAddressWithReplyTo(self):
        """
        Test that L{Part.relatedAddresses} yields a sender address taken from
        the C{Reply-To} header of a message, if that header is present and the
        C{From} and C{Sender} headers are not.
        """
        self.headers['from'] = self.headers['sender'] = ''
        self._relationTest(self.headers, SENDER_RELATION, self.replyToEmail,
                           self.replyToDisplay)

    def test_recipientRelation(self):
        """
        Test that L{Part.relatedAddresses} yields a recipient address taken
        from the C{To} header of the message, if that header is present.
        """
        self._relationTest(self.headers, RECIPIENT_RELATION, self.toEmail,
                           self.toDisplay)

    def test_copyRelation(self):
        """
        Test that L{Part.relatedAddresses} yields a recipient address taken
        from the C{Cc} header of the message, if that header is present.
        """
        self._relationTest(self.headers, COPY_RELATION, self.ccEmail,
                           self.ccDisplay)

    def test_multiRelation(self):
        """
        Test that L{Part.relatedAddresses} yields multiple recipient addresses
        taken from the C{Cc} header of the message, if multiples were found.
        """
        self.headers['cc'] = self._header(
            'Cc', self.ccAddress + u", " + self.bccAddress)

        msgSource = msg(relatedAddressesMessage % self.headers)

        def checkRelations(msg):
            ccAddrs = [(addr.email, addr.display)
                       for (kind, addr) in msg.relatedAddresses()
                       if kind == COPY_RELATION]
            self.assertEqual([(self.ccEmail, self.ccDisplay),
                              (self.bccEmail, self.bccDisplay)], ccAddrs)

        self._messageTest(msgSource, checkRelations)

    def test_blindCopyRelation(self):
        """
        Test that L{Part.relatedAddresses} yields a recipient address taken
        from the C{Bcc} header of the message, if that header is present.
        """
        self._relationTest(self.headers, BLIND_COPY_RELATION, self.bccEmail,
                           self.bccDisplay)

    def test_resentToRelation(self):
        """
        Test that L{Part.relatedAddresses} yields a 'resent to' address taken
        from the C{Resent-To} header of the message, if that header is present
        """
        self._relationTest(self.headers, RESENT_TO_RELATION,
                           self.resentToEmail, self.resentToDisplay)

    def test_resentFromRelation(self):
        """
        Test that L{Part.relatedAddresses} yields a 'resent from' address taken
        from the C{Resent-From} header of the message, if that header is present
        """
        self._relationTest(self.headers, RESENT_FROM_RELATION,
                           self.resentFromEmail, self.resentFromDisplay)

    def test_noRelations(self):
        """
        Test that L{Part.relatedAddresses} gives back an empty iterator if
        there are no usable headers in the message.
        """
        msgSource = msg(
            relatedAddressesMessage % {
                'from': '',
                'sender': '',
                'reply-to': '',
                'cc': '',
                'to': '',
                'bcc': '',
                'resent-from': '',
                'resent-to': ''
            })

        def checkRelations(msg):
            self.assertEqual(list(msg.relatedAddresses()), [])

        self._messageTest(msgSource, checkRelations)

    alternateMessage = PartMaker('multipart/alternative', 'alt',
                                 PartMaker('text/plain', 'plain'),
                                 PartMaker('text/html', 'html')).make()

    def test_getAlternatesAlternate(self):
        """
        Test that L{xquotient.mimestorage.Part.getAlternates} returns
        C{text/html} as the alternate for a C{text/plain} part inside a
        C{multipart/alternative} part
        """
        def checkAlternates(p):
            (alt, plain, html) = p.walk()
            self.assertEqual(list(plain.getAlternates()),
                             [('text/html', html)])

        self._messageTest(self.alternateMessage, checkAlternates)
Exemple #11
0
class PersistenceTestCase(unittest.TestCase, MessageTestMixin,
                          PersistenceMixin):
    alternative = PartMaker('multipart/alternative', 'alt',
                            PartMaker('text/plain', 'plain-1'),
                            PartMaker('text/html', 'html-1'),
                            PartMaker('image/jpeg', 'hi')).make()

    def test_readableParts(self):
        """
        Test that L{xquotient.mimestorage.Part.readableParts} returns the
        text/plain and text/html parts inside a multipart/alternative
        """
        def checkReadable(part):
            self.assertEquals(
                list(p.getContentType() for p in part.readableParts()),
                ['text/plain', 'text/html'])

        self._messageTest(self.alternative, checkReadable)

    def assertIndexability(self, msg):
        fi = ixmantissa.IFulltextIndexable(msg.message)
        self.assertEquals(fi.uniqueIdentifier(), unicode(msg.message.storeID))
        # XXX: the following success fixtures are sketchy.  the
        # '*****@*****.**' token appears twice because it is both the
        # 'senderDisplay' and the 'sender' of this message.  That strikes me as
        # wrong; it should eliminate the duplicate, and not rely on the details
        # of the attributes of Message, since ideally those attributes would be
        # accessed through the Correspondent item anyway. --glyph
        self.assertEquals(sorted(fi.textParts()), [
            u'Hello Bob,\n  How are you?\n-A\n',
            u'a test message, comma separated',
            u'[email protected] alice example com',
            u'[email protected] bob example com'
        ])
        self.assertEquals(
            fi.keywordParts(), {
                u'subject': u'a test message, comma separated',
                u'from': u'[email protected] alice example com',
                u'to': u'[email protected] bob example com'
            })
        self.assertEquals(fi.documentType(), msg.message.typeName)

    def test_unknownMultipartTypeAsMixed(self):
        """
        Test that unknown multipart mime types are rendered with 'multipart/mixed'
        content types (with their original content).

          Any "multipart" subtypes that an implementation does not recognize
          must be treated as being of subtype "mixed".

        RFC 2046, Section 5.1.3
        """
        content = PartMaker('multipart/appledouble', 'appledouble',
                            PartMaker('text/applefile', 'applefile'),
                            PartMaker('image/jpeg', 'jpeg')).make()
        part = self.setUpMailStuff().feedStringNow(content)
        walkedPart = part.walkMessage('image/jpeg').next()
        self.assertEquals(walkedPart.type, 'multipart/mixed')
        self.assertEquals(walkedPart.part, part)

    def test_unknownTypeAsOctetStream(self):
        """
        Test that unknown non-multipart mime types are rendered as
        'application/octet-stream'.

        See RFC 2046, Section 4 for more details.
        """
        content = PartMaker('image/applefile', 'applefile').make()
        part = self.setUpMailStuff().feedStringNow(content)
        walkedPart = part.walkMessage(None).next()
        self.assertEquals(walkedPart.type, 'application/octet-stream')
        self.assertEquals(walkedPart.part, part)

    def testIndexability(self):
        """
        Test that the result is adaptable to IFulltextIndexable and the
        resulting object spits out the right data.
        """
        self._messageTest(self.trivialMessage, self.assertIndexability)

    def testAttachmentsAllHaveLength(self):
        def checkAttachments(msgitem):
            for att in msgitem.walkAttachments():
                self.assertNotEquals(att.part.bodyLength, None)
                self.assertNotEquals(att.part.bodyLength, 0)

        self._messageTest(messageWithEmbeddedMessage, checkAttachments)
        self._messageTest(truncatedMultipartMessage, checkAttachments)

    def testRFC822PartLength(self):
        """
        Ensure that message/rfc822 parts have the correct bodyLength.
        """
        def checkAttachments(msgitem):
            for att in msgitem.walkAttachments():
                if att.part.getContentType() == u"message/rfc822":
                    self.assertEquals(att.part.bodyLength, 3428)

        self._messageTest(messageWithEmbeddedMessage, checkAttachments)

    def testPartIDs(self):
        mr = self.setUpMailStuff()
        part = mr.feedStringNow(self.multipartMessage)
        self.assertEquals(part.partID, 0)
        partIDs = list(
            part.store.query(Part,
                             sort=Part.partID.ascending).getColumn('partID'))
        self.assertEquals(partIDs, range(len(partIDs)))

    alternativeInsideMixed = PartMaker(
        'multipart/mixed', 'mixed',
        PartMaker('multipart/alternative', 'alt',
                  PartMaker('text/plain', 'plain-1'),
                  PartMaker('text/html', 'html-1')),
        PartMaker('text/plain', 'plain-2')).make()

    def testAlternativeInsideMixed(self):
        part = self.setUpMailStuff().feedStringNow(self.alternativeInsideMixed)

        self.assertEquals(part.getContentType(), 'multipart/mixed')

        def getKidsAndCheckTypes(parent, types):
            kids = list(part.store.query(Part, Part.parent == parent))
            self.assertEquals(list(p.getContentType() for p in kids), types)
            return kids

        kids = getKidsAndCheckTypes(part,
                                    ['multipart/alternative', 'text/plain'])

        # RFC 2046, section 5.1.1, says:
        #    "The CRLF preceding the boundary delimiter line is conceptually attached
        #     to the boundary so that it is possible to have a part that does not end
        #     with a CRLF (line break). Body parts that must be considered to end with
        #     line breaks, therefore, must have two CRLFs preceding the boundary
        #     delimiter line, the first of which is part of the preceding body part,
        #     and the second of which is part of the encapsulation boundary."
        #
        # - there is only one CRLF between the end of the body of each part
        # and the next boundary, which would seem to indicate that we shouldn't
        # have to to embed newlines to get these assertions to pass

        self.assertEquals(kids[-1].getBody(), 'plain-2\n')

        gkids = getKidsAndCheckTypes(kids[0], ['text/plain', 'text/html'])

        self.assertEquals(gkids[0].getBody(), 'plain-1\n')
        self.assertEquals(gkids[1].getBody(), 'html-1\n')

        def checkDisplayBodies(parent, ctype, bodies):
            displayParts = list(parent.walkMessage(ctype))
            self.assertEquals(list(p.part.getBody() for p in displayParts),
                              bodies)

        # we're calling walkMessage() on the multipart/mixed part,
        # so we should get back 'plain-1' and 'plain-2', not 'html-1',
        # because it's inside a nested multipart/alternative with 'plain-1'

        checkDisplayBodies(part, 'text/plain', ['plain-1\n', 'plain-2\n'])

        # this should still show us 'plain-2', but 'html-1' should get
        # selected from the multipart/alternative part

        checkDisplayBodies(part, 'text/html', ['html-1\n', 'plain-2\n'])

        # now try the same on the multipart/alternative part directly.
        # the results should be the same, except plain-2 shouldn't be
        # considered, because it's a sibling part

        checkDisplayBodies(kids[0], 'text/plain', ['plain-1\n'])
        checkDisplayBodies(kids[0], 'text/html', ['html-1\n'])

    typelessMessage = msg("""\
To: you
From: nobody

haha
""")

    def testContentTypeNotNone(self):
        self._messageTest(
            self.typelessMessage, lambda part: self.assertEquals(
                part.getContentType(), 'text/plain'))

    datelessMessage = msg("""\
Received: Wed, 15 Feb 2006 03:58:50 GMT

Some body
""")

    def testSentWhen(self):
        def assertSentWhen(part):
            self.assertEquals(
                part.message.sentWhen,
                extime.Time.fromRFC2822("Wed, 15 Feb 2006 03:58:50 GMT"))

        self._messageTest(self.datelessMessage, assertSentWhen)
Exemple #12
0
class RenderingTestCase(TestCase, MIMEReceiverMixin):
    aBunchOfRelatedParts = PartMaker(
        'multipart/related', 'related',
        *(list(
            PartMaker('text/html', '<p>html-' + str(i) + '</p>')
            for i in xrange(100)) +
          list(PartMaker('image/gif', '') for i in xrange(100)))).make()

    def setUp(self):
        """
        Make a copy of the very minimal database for a single test method to
        mangle.
        """
        receiver = self.setUpMailStuff()
        makeMessage(receiver, self.aBunchOfRelatedParts, None)

    def test_messageRendering(self):
        """
        Test rendering of message detail for an extremely complex message.
        """
        msg = self.substore.findUnique(Message)
        msg.classifyClean()
        return renderLivePage(ThemedFragmentWrapper(MessageDetail(msg)))

    def test_inboxRendering(self):
        """
        Test rendering of the inbox with a handful of extremely complex
        messages in it.
        """
        def deliverMessages():
            for i in xrange(5):
                makeMessage(self.createMIMEReceiver(),
                            self.aBunchOfRelatedParts, None)

        self.substore.transact(deliverMessages)

        inbox = self.substore.findUnique(Inbox)

        composer = compose.Composer(store=self.substore)
        installOn(composer, self.substore)

        return renderLivePage(ThemedFragmentWrapper(InboxScreen(inbox)))

    def test_inboxComposeFragmentRendering(self):
        """
        Test rendering of the L{xquotient.compose.ComposeFragment} returned
        from L{xquotient.inbox.InboxScreen.getComposer}
        """
        installOn(compose.Composer(store=self.substore), self.substore)

        inbox = self.substore.findUnique(Inbox)
        inboxScreen = InboxScreen(inbox)

        composeFrag = inboxScreen.getComposer()

        return renderLivePage(ThemedFragmentWrapper(composeFrag))

    def test_peopleMessageListRendering(self):
        mlister = MessageLister(store=self.substore)
        installOn(mlister, self.substore)

        p = Person(store=self.substore, name=u'Bob')

        EmailAddress(store=self.substore, person=p, address=u'bob@internet')

        for i in xrange(5):
            testMessageFactory(store=self.substore,
                               subject=unicode(str(i)),
                               receivedWhen=Time(),
                               spam=False,
                               sender=u'bob@internet')

        self.assertEqual(len(list(mlister.mostRecentMessages(p))), 5)
        return renderPage(
            rend.Page(docFactory=loaders.stan(MessageList(mlister, p))))