1"""
2Tests for L{nevow.testutil} -- a module of utilities for testing Nevow
3applications.
4"""
5
6import sys
7
8from unittest import TestResult
9
10from twisted.python.filepath import FilePath
11from twisted.trial.unittest import TestCase, SkipTest
12from twisted.web.http import OK, BAD_REQUEST
13
14from nevow.testutil import FakeRequest, renderPage, JavaScriptTestCase
15from nevow.testutil import NotSupported
16from nevow.url import root
17from nevow.rend import Page
18from nevow.loaders import stan
19
20
21class TestFakeRequest(TestCase):
22    """
23    Bad tests for L{FakeRequest}.
24
25    These tests verify that L{FakeRequest} has some behavior, but not that
26    that behavior is the same as the behavior of an actual request object.
27    In other words, these tests do not actually verify the fake.  They
28    should be replaced with something which verifies that L{FakeRequest} and
29    L{NevowRequest} actually have the same behavior.
30    """
31    def test_fields(self):
32        """
33        L{FakeRequest.fields} is C{None} for all fake requests.
34        """
35        self.assertIdentical(FakeRequest().fields, None)
36
37
38    def test_prePathURL(self):
39        """
40        Verify that L{FakeRequest.prePathURL} returns the prepath of the
41        requested URL.
42        """
43        req = FakeRequest(currentSegments=['a'], uri='/a/b')
44        self.assertEqual(req.prePathURL(), 'http://localhost/a')
45
46
47    def test_prePathURLHost(self):
48        """
49        Verify that L{FakeRequest.prePathURL} will turn the C{Host} header of
50        the request into the netloc of the returned URL, if it's present.
51        """
52        req = FakeRequest(currentSegments=['a', 'b'],
53                          uri='/a/b/c/',
54                          headers={'host': 'foo.bar'})
55        self.assertEqual(req.prePathURL(), 'http://foo.bar/a/b')
56
57
58    def test_getRootURL(self):
59        """
60        L{FakeRequest.getRootURL} returns C{None} when
61        L{FakeRequest.rememberRootURL} has not yet been called.  After
62        L{FakeRequest.rememberRootURL} has been called,
63        L{FakeRequest.getRootURL} returns the value which was passed to it.
64        """
65        request = FakeRequest()
66        self.assertIdentical(request.getRootURL(), None)
67        request.rememberRootURL("foo/bar")
68        self.assertEqual(request.getRootURL(), "foo/bar")
69
70
71    def test_headers(self):
72        """
73        Check that setting a header with L{FakeRequest.setHeader} actually
74        places it in the headers dictionary.
75        """
76        host = 'divmod.com'
77        req = FakeRequest()
78        req.setHeader('host', host)
79        self.assertEqual(req.responseHeaders.getRawHeaders('host'), [host])
80
81
82    def test_caseInsensitiveHeaders(self):
83        """
84        L{FakeRequest.getHeader} will return the value of a header regardless
85        of casing.
86        """
87        host = 'example.com'
88        request = FakeRequest()
89        request.requestHeaders.setRawHeaders('host', [host])
90        self.assertEqual(request.getHeader('hOsT'), host)
91
92
93    def test_smashInitialHeaderCase(self):
94        """
95        L{FakeRequest.getHeader} will return the value of a header specified to
96        L{FakeRequest.__init__} even if the header names have differing case.
97        """
98        host = 'example.com'
99        request = FakeRequest(headers={'HoSt': host})
100        self.assertEqual(request.getHeader('hOsT'), host)
101
102
103    def test_urls(self):
104        """
105        Check that rendering URLs via L{renderPage} actually works.
106        """
107        class _URLPage(Page):
108            docFactory = stan(
109                root.child('foo'))
110
111        def _checkForUrl(result):
112            return self.assertEquals('http://localhost/foo', result)
113
114        return renderPage(_URLPage()).addCallback(_checkForUrl)
115
116
117    def test_defaultResponseCode(self):
118        """
119        Test that the default response code of a fake request is success.
120        """
121        self.assertEqual(FakeRequest().code, OK)
122
123
124    def test_setResponseCode(self):
125        """
126        Test that the response code of a fake request can be set.
127        """
128        req = FakeRequest()
129        req.setResponseCode(BAD_REQUEST)
130        self.assertEqual(req.code, BAD_REQUEST)
131
132
133    def test_headerSeparation(self):
134        """
135        Request headers and response headers are different things.
136
137        Test that they are handled separately.
138        """
139        req = FakeRequest()
140        req.setHeader('foo', 'bar')
141        self.assertFalse(req.requestHeaders.hasHeader('foo'))
142        self.assertEqual(req.getHeader('foo'), None)
143        req.requestHeaders.setRawHeaders('foo', ['bar'])
144        self.assertEqual(req.getHeader('foo'), 'bar')
145
146
147
148    def test_path(self):
149        """
150        Test that the path attribute of a fake request is set.
151        """
152        req = FakeRequest(uri='/foo')
153        self.assertEqual(req.path, '/foo')
154
155
156
157class JavaScriptTests(TestCase):
158    """
159    Tests for the JavaScript UnitTest runner, L{JavaScriptTestCase}.
160    """
161    def setUp(self):
162        """
163        Create a L{JavaScriptTestCase} and verify that its dependencies are
164        present (otherwise, skip the test).
165        """
166        self.case = JavaScriptTestCase()
167        try:
168            self.case.checkDependencies()
169        except NotSupported:
170            raise SkipTest("Missing JS dependencies")
171
172
173    def test_unsuccessfulExit(self):
174        """
175        Verify that an unsuccessful exit status results in an error.
176        """
177        result = TestResult()
178        self.case.createSource = lambda testMethod: "throw new TypeError();"
179        self.case.run(result)
180        self.assertEqual(len(result.errors), 1)
181        self.assertTrue(
182            result.errors[0][1].startswith(
183                'Exception: JavaScript interpreter had error exit: '))
184
185
186    def test_signalledExit(self):
187        """
188        An error should be reported if the JavaScript interpreter exits because
189        it received a signal.
190        """
191        segfault = FilePath(self.mktemp())
192        segfault.setContent("""\
193#!/usr/bin/python
194# Generate an unhandled SIGSEGV for this process immediately upon import.
195
196import os, signal
197os.kill(os.getpid(), signal.SIGSEGV)
198""")
199
200        def stubFinder():
201            return sys.executable
202        def stubScript(testModule):
203            return segfault.path
204        self.case.findJavascriptInterpreter = stubFinder
205        self.case.makeScript = stubScript
206        result = TestResult()
207        self.case.run(result)
208        self.assertEqual(len(result.errors), 1)
209        self.assertEquals(
210            result.errors[0][1],
211            'Exception: JavaScript interpreter exited due to signal 11\n')
212
213
214    def test_missingJavaScriptClass(self):
215        """
216        If a JavaScript class required by the test code is unavailable, an
217        error is added to the result object by L{JavaScriptTestCase.run}.
218        """
219        result = TestResult()
220        self.case.testMethod = lambda: "Nevow.Test.NoSuchModule"
221        self.case.run(result)
222        self.assertEqual(len(result.errors), 1)
223