~glyph/divmod.org/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
"""
This module tests the code listings used in the documentation.
"""

import sys

from twisted.python.filepath import FilePath
from twisted.trial.unittest import SkipTest, TestCase

from nevow._widget_plugin import ElementRenderingLivePage
from nevow.testutil import renderLivePage, JavaScriptTestCase
from nevow.athena import jsDeps, expose

from nevow import plugins


class ExampleTestBase(object):
    """
    This is a mixin which adds an example to the path, tests it, and then
    removes it from the path and unimports the modules which the test loaded.
    Test cases which test example code and documentation listings should use
    this.

    This is done this way so that examples can live in isolated path entries,
    next to the documentation, replete with their own plugin packages and
    whatever other metadata they need.  Also, example code is a rare instance
    of it being valid to have multiple versions of the same code in the
    repository at once, rather than relying on version control, because
    documentation will often show the progression of a single piece of code as
    features are added to it, and we want to test each one.
    """

    examplePath = None

    def setUp(self):
        """
        Add our example directory to the path and record which modules are
        currently loaded.
        """
        self.originalPath = sys.path[:]
        self.originalModules = sys.modules.copy()
        here = FilePath(__file__).parent().parent().parent()
        for childName in self.examplePath:
            here = here.child(childName)
        if not here.exists():
            raise SkipTest("Examples (%s) not found - cannot test" % (here.path,))
        sys.path.append(here.path)
        # This stuff is pretty horrible; we need to turn off JS caching for the
        # duration of this test (this flag will be set back to True by the
        # plugin-loading itself, so no need to clean it up) because the
        # previously-loaded list of plugins is going to be invalid.
        jsDeps._loadPlugins = True
        # Even more horrible!  nevow.plugins.__path__ needs to be recomputed
        # each time for the new value of sys.path.
        reload(plugins)


    def tearDown(self):
        """
        Remove the example directory from the path and remove all modules loaded by
        the test from sys.modules.
        """
        sys.modules.clear()
        sys.modules.update(self.originalModules)
        sys.path[:] = self.originalPath
        reload(plugins)



class ExampleJavaScriptTestCase(JavaScriptTestCase):
    """
    Since JavaScriptTestCase does not use setUp and tearDown, we can't use
    simple inheritance to invoke the functionality in ExampleTestBase; so,
    instead, this class composes JavaScriptTestCase with a ExampleTestBase.
    """
    def run(self, result):
        """
        Wrap L{JavaScriptTestCase.run} to change and restore the plugin environment
        on each test run.
        """
        base = ExampleTestBase()
        base.examplePath = self.examplePath
        try:
            base.setUp()
        except SkipTest, e:
            result.startTest(self)
            result.addSkip(self, str(e))
            result.stopTest(self)
        else:
            try:
                return JavaScriptTestCase.run(self, result)
            finally:
                base.tearDown()


def chatListing(partname):
    """
    Return a list of strings that represents a path from the root of the Nevow
    source package which contains a potential PYTHONPATH entry with some
    listing code in it, based on which part of the chat tutorial it came from.
    """
    return ['doc', 'howto', 'chattutorial', 'part'+partname, 'listings']



class Part00Tests(ExampleJavaScriptTestCase):
    """
    Refer to JavaScript unit tests for section 01 of the tutorial.
    """

    examplePath = chatListing('00')

    def test_part00(self):
        """
        Test method pointing to part 00 of the tutorial.
        """
        return 'Nevow.Test.TestHowtoListing00'



class Echo00(ExampleTestBase, TestCase):
    """
    These tests will make sure that the very basic 'echobox' portion of the
    tutorial works.
    """
    examplePath = chatListing('00')

    def test_renderEcho(self):
        """
        Rendering the echo example element should produce a very simple text area.
        """
        from echothing.echobox import EchoElement
        TEXT = 'Echo Element'
        eb = EchoElement()
        erlp = ElementRenderingLivePage(eb)
        def checkContent(result):
            # The "liveElement" renderer inserts this, let's look for it to
            # make sure it rendered live:
            self.assertIn('id="athena:'+str(eb._athenaID)+'"', result)
            self.assertIn('athena:class="EchoThing.EchoWidget"', result)
            self.assertIn(TEXT, result)
        return renderLivePage(erlp).addCallback(checkContent)


    def test_echoTellsClient(self):
        """
        When 'hear' is called on a ChatterElement, it should inform its client of what
        was said and by whom.
        """
        from echothing.echobox import EchoElement
        eb = EchoElement()
        echoed = []
        eb.callRemote = lambda method, message: echoed.append((method, message))
        eb.say(u'HELLO... Hello... hello...')
        self.assertEquals(echoed, [('addText', u'HELLO... Hello... hello...')])



class Part01Tests(ExampleJavaScriptTestCase):
    """
    Refer to JavaScript unit tests for section 01 of the tutorial.
    """

    examplePath = chatListing('01')

    def test_part01(self):
        """
        Test method pointing to part 01 of the tutorial.
        """
        return 'Nevow.Test.TestHowtoListing01'



class RenderAndChat01(ExampleTestBase, TestCase):
    """
    These tests make sure that the listing for part 01 of the chatterbox
    tutorial will import, render, and allow users to chat with each other.
    """

    examplePath = chatListing('01')

    def test_basicRendering(self):
        """
        Rendering the example element should produce a chat area.
        """
        from chatthing.chatterbox import ChatterElement, ChatRoom
        PROMPT = 'Choose your username: '
        cb = ChatterElement(ChatRoom())
        erlp = ElementRenderingLivePage(cb)
        def checkContent(result):
            # The "liveElement" renderer inserts this, let's look for it to
            # make sure it rendered live:
            self.assertIn('id="athena:'+str(cb._athenaID)+'"', result)
            self.assertIn('athena:class="ChatThing.ChatterWidget"', result)
            self.assertIn(PROMPT, result)
        return renderLivePage(erlp).addCallback(checkContent)


    def test_username(self):
        """
        When a user sets their username in the chat room, it should set an
        attribute on their ChatterElement instance.
        """
        from chatthing.chatterbox import ChatterElement, ChatRoom
        cb = ChatterElement(ChatRoom())
        setUsername = expose.get(cb, 'setUsername')
        setUsername(u'jethro')
        self.assertIdentical(u'jethro', cb.username)


    def test_loginThenWall(self):
        """
        When a user logs in the 'wall' method on their ChatterElement gets called,
        notifiying everyone in the room that they have entered.
        """
        from chatthing.chatterbox import ChatRoom
        jethroHeard = []
        cletusHeard = []
        cr = ChatRoom()
        user1 = cr.makeChatter()
        user1.wall = lambda msg: jethroHeard.append(msg)
        user1.setUsername(u'jethro')
        user2 = cr.makeChatter()
        user2.wall = lambda msg: cletusHeard.append(msg)
        user2.setUsername(u'cletus')
        self.assertEquals(jethroHeard,
                          [u' * user jethro has joined the room',
                           u' * user cletus has joined the room'])
        self.assertEquals(cletusHeard, [u' * user cletus has joined the room'])


    def test_sayThenHear(self):
        """
        When a user calls the 'say' method on their ChatterElement, everyone (including
        them) should 'hear' it.
        """
        from chatthing.chatterbox import ChatRoom
        cr = ChatRoom()
        user1 = cr.makeChatter()
        user1.wall = lambda msg: msg
        user1.setUsername(u'jethro')
        user2 = cr.makeChatter()
        user2.wall = lambda msg: msg
        user2.setUsername(u'cletus')
        jethroHeard = []
        cletusHeard = []
        user1.hear = lambda who, what: jethroHeard.append((who,what))
        user2.hear = lambda who, what: cletusHeard.append((who,what))
        say = expose.get(user1, 'say')
        say(u'Hey, Cletus!')
        self.assertEquals(jethroHeard, cletusHeard)
        self.assertEquals(cletusHeard, [(u'jethro', u'Hey, Cletus!')])


    def test_wallTellsClient(self):
        """
        When 'wall' is called on a ChatterElement, it should inform its client of
        the message.
        """
        from chatthing.chatterbox import ChatRoom
        cb = ChatRoom().makeChatter()
        heard = []
        cb.callRemote = lambda method, msg: heard.append((method, msg))
        cb.wall(u'Message for everyone...')
        self.assertEquals(heard, [('displayMessage', u'Message for everyone...')])

    def test_hearTellsClient(self):
        """
        When 'hear' is called on a ChatterElement, it should inform its client of what
        was said and by whom.
        """
        from chatthing.chatterbox import ChatRoom
        cb = ChatRoom().makeChatter()
        heard = []
        cb.callRemote = lambda method, who, what: heard.append((method, who, what))
        cb.hear(u'Hello', u'Chat')
        self.assertEquals(heard, [('displayUserMessage', u'Hello', u'Chat')])