Bowe Strickland
2018-10-27 6e49871feaa1a60549206cf5512c9fb7f3d5fd56
commit | author | age
1ffb8e 1 import unittest
6df90b 2
0c29cf 3 from pyramid.compat import bytes_, string_types, text_
MM 4
1ffb8e 5
f8f08b 6 class Test_exception_response(unittest.TestCase):
99edc5 7     def _callFUT(self, *arg, **kw):
f8f08b 8         from pyramid.httpexceptions import exception_response
0c29cf 9
f8f08b 10         return exception_response(*arg, **kw)
99edc5 11
7740b6 12     def test_status_400(self):
TS 13         from pyramid.httpexceptions import HTTPBadRequest
0c29cf 14
7740b6 15         self.assertTrue(isinstance(self._callFUT(400), HTTPBadRequest))
TS 16
99edc5 17     def test_status_404(self):
CM 18         from pyramid.httpexceptions import HTTPNotFound
0c29cf 19
7740b6 20         self.assertTrue(isinstance(self._callFUT(404), HTTPNotFound))
TS 21
22     def test_status_500(self):
23         from pyramid.httpexceptions import HTTPInternalServerError
0c29cf 24
MM 25         self.assertTrue(
26             isinstance(self._callFUT(500), HTTPInternalServerError)
27         )
99edc5 28
CM 29     def test_status_201(self):
30         from pyramid.httpexceptions import HTTPCreated
0c29cf 31
7740b6 32         self.assertTrue(isinstance(self._callFUT(201), HTTPCreated))
99edc5 33
CM 34     def test_extra_kw(self):
c6a950 35         resp = self._callFUT(404, headers=[('abc', 'def')])
99edc5 36         self.assertEqual(resp.headers['abc'], 'def')
c6a950 37
0c29cf 38
99edc5 39 class Test_default_exceptionresponse_view(unittest.TestCase):
CM 40     def _callFUT(self, context, request):
41         from pyramid.httpexceptions import default_exceptionresponse_view
0c29cf 42
99edc5 43         return default_exceptionresponse_view(context, request)
CM 44
45     def test_call_with_exception(self):
46         context = Exception()
47         result = self._callFUT(context, None)
48         self.assertEqual(result, context)
49
50     def test_call_with_nonexception(self):
51         request = DummyRequest()
52         context = Exception()
53         request.exception = context
54         result = self._callFUT(None, request)
55         self.assertEqual(result, context)
56
0c29cf 57
99edc5 58 class Test__no_escape(unittest.TestCase):
CM 59     def _callFUT(self, val):
60         from pyramid.httpexceptions import _no_escape
0c29cf 61
99edc5 62         return _no_escape(val)
CM 63
64     def test_null(self):
65         self.assertEqual(self._callFUT(None), '')
66
67     def test_not_basestring(self):
68         self.assertEqual(self._callFUT(42), '42')
69
70     def test_unicode(self):
71         class DummyUnicodeObject(object):
72             def __unicode__(self):
e6c2d2 73                 return text_('42')
0c29cf 74
99edc5 75         duo = DummyUnicodeObject()
e6c2d2 76         self.assertEqual(self._callFUT(duo), text_('42'))
0c29cf 77
99edc5 78
97ed56 79 class TestHTTPException(unittest.TestCase):
99edc5 80     def _getTargetClass(self):
97ed56 81         from pyramid.httpexceptions import HTTPException
0c29cf 82
97ed56 83         return HTTPException
99edc5 84
0c29cf 85     def _getTargetSubclass(
MM 86         self,
87         code='200',
88         title='OK',
89         explanation='explanation',
90         empty_body=False,
91     ):
99edc5 92         cls = self._getTargetClass()
0c29cf 93
99edc5 94         class Subclass(cls):
CM 95             pass
0c29cf 96
99edc5 97         Subclass.empty_body = empty_body
CM 98         Subclass.code = code
99         Subclass.title = title
100         Subclass.explanation = explanation
101         return Subclass
102
103     def _makeOne(self, *arg, **kw):
104         cls = self._getTargetClass()
105         return cls(*arg, **kw)
106
107     def test_implements_IResponse(self):
108         from pyramid.interfaces import IResponse
0c29cf 109
99edc5 110         cls = self._getTargetClass()
366a5c 111         self.assertTrue(IResponse.implementedBy(cls))
99edc5 112
CM 113     def test_provides_IResponse(self):
114         from pyramid.interfaces import IResponse
0c29cf 115
99edc5 116         inst = self._getTargetClass()()
366a5c 117         self.assertTrue(IResponse.providedBy(inst))
99edc5 118
CM 119     def test_implements_IExceptionResponse(self):
120         from pyramid.interfaces import IExceptionResponse
0c29cf 121
99edc5 122         cls = self._getTargetClass()
366a5c 123         self.assertTrue(IExceptionResponse.implementedBy(cls))
99edc5 124
CM 125     def test_provides_IExceptionResponse(self):
126         from pyramid.interfaces import IExceptionResponse
0c29cf 127
99edc5 128         inst = self._getTargetClass()()
366a5c 129         self.assertTrue(IExceptionResponse.providedBy(inst))
99edc5 130
CM 131     def test_ctor_sets_detail(self):
132         exc = self._makeOne('message')
133         self.assertEqual(exc.detail, 'message')
134
135     def test_ctor_sets_comment(self):
136         exc = self._makeOne(comment='comment')
137         self.assertEqual(exc.comment, 'comment')
138
139     def test_ctor_calls_Exception_ctor(self):
140         exc = self._makeOne('message')
141         self.assertEqual(exc.message, 'message')
142
143     def test_ctor_calls_Response_ctor(self):
144         exc = self._makeOne('message')
88fcdc 145         self.assertEqual(exc.status, '520 Unknown Error')
99edc5 146
CM 147     def test_ctor_extends_headers(self):
148         exc = self._makeOne(headers=[('X-Foo', 'foo')])
149         self.assertEqual(exc.headers.get('X-Foo'), 'foo')
150
151     def test_ctor_sets_body_template_obj(self):
152         exc = self._makeOne(body_template='${foo}')
153         self.assertEqual(
0c29cf 154             exc.body_template_obj.substitute({'foo': 'foo'}), 'foo'
MM 155         )
99edc5 156
CM 157     def test_ctor_with_empty_body(self):
158         cls = self._getTargetSubclass(empty_body=True)
159         exc = cls()
160         self.assertEqual(exc.content_type, None)
161         self.assertEqual(exc.content_length, None)
162
163     def test_ctor_with_body_doesnt_set_default_app_iter(self):
8e606d 164         exc = self._makeOne(body=b'123')
475532 165         self.assertEqual(exc.app_iter, [b'123'])
99edc5 166
CM 167     def test_ctor_with_unicode_body_doesnt_set_default_app_iter(self):
e6c2d2 168         exc = self._makeOne(unicode_body=text_('123'))
475532 169         self.assertEqual(exc.app_iter, [b'123'])
99edc5 170
CM 171     def test_ctor_with_app_iter_doesnt_set_default_app_iter(self):
475532 172         exc = self._makeOne(app_iter=[b'123'])
CM 173         self.assertEqual(exc.app_iter, [b'123'])
99edc5 174
CM 175     def test_ctor_with_body_sets_default_app_iter_html(self):
176         cls = self._getTargetSubclass()
177         exc = cls('detail')
53d11e 178         environ = _makeEnviron()
d0a5f0 179         environ['HTTP_ACCEPT'] = 'text/html'
53d11e 180         start_response = DummyStartResponse()
CM 181         body = list(exc(environ, start_response))[0]
8e606d 182         self.assertTrue(body.startswith(b'<html'))
CM 183         self.assertTrue(b'200 OK' in body)
184         self.assertTrue(b'explanation' in body)
185         self.assertTrue(b'detail' in body)
c6a950 186
99edc5 187     def test_ctor_with_body_sets_default_app_iter_text(self):
CM 188         cls = self._getTargetSubclass()
189         exc = cls('detail')
53d11e 190         environ = _makeEnviron()
CM 191         start_response = DummyStartResponse()
192         body = list(exc(environ, start_response))[0]
8e606d 193         self.assertEqual(body, b'200 OK\n\nexplanation\n\n\ndetail\n\n')
99edc5 194
CM 195     def test__str__detail(self):
196         exc = self._makeOne()
197         exc.detail = 'abc'
198         self.assertEqual(str(exc), 'abc')
c6a950 199
99edc5 200     def test__str__explanation(self):
CM 201         exc = self._makeOne()
202         exc.explanation = 'def'
203         self.assertEqual(str(exc), 'def')
204
205     def test_wsgi_response(self):
206         exc = self._makeOne()
207         self.assertTrue(exc is exc.wsgi_response)
208
209     def test_exception(self):
210         exc = self._makeOne()
211         self.assertTrue(exc is exc.exception)
212
53d11e 213     def test__calls_start_response(self):
CM 214         cls = self._getTargetSubclass()
215         exc = cls()
216         environ = _makeEnviron()
217         start_response = DummyStartResponse()
218         exc(environ, start_response)
219         self.assertTrue(start_response.headerlist)
220         self.assertEqual(start_response.status, '200 OK')
221
85093d 222     def test_call_returns_same_body_called_twice(self):
CM 223         # optimization
224         cls = self._getTargetSubclass()
225         exc = cls()
226         environ = _makeEnviron()
227         environ['HTTP_ACCEPT'] = '*/*'
228         start_response = DummyStartResponse()
229         app_iter = exc(environ, start_response)
230         self.assertEqual(app_iter[0], exc.body)
231
99edc5 232     def test__default_app_iter_no_comment_plain(self):
CM 233         cls = self._getTargetSubclass()
234         exc = cls()
53d11e 235         environ = _makeEnviron()
CM 236         start_response = DummyStartResponse()
237         body = list(exc(environ, start_response))[0]
4061d5 238         for header in start_response.headerlist:
BJR 239             if header[0] == 'Content-Type':
240                 self.assertEqual(header[1], 'text/plain; charset=UTF-8')
8e606d 241         self.assertEqual(body, b'200 OK\n\nexplanation\n\n\n\n\n')
99edc5 242
CM 243     def test__default_app_iter_with_comment_plain(self):
244         cls = self._getTargetSubclass()
245         exc = cls(comment='comment')
53d11e 246         environ = _makeEnviron()
CM 247         start_response = DummyStartResponse()
248         body = list(exc(environ, start_response))[0]
4061d5 249         for header in start_response.headerlist:
BJR 250             if header[0] == 'Content-Type':
251                 self.assertEqual(header[1], 'text/plain; charset=UTF-8')
8e606d 252         self.assertEqual(body, b'200 OK\n\nexplanation\n\n\n\ncomment\n')
4061d5 253
99edc5 254     def test__default_app_iter_no_comment_html(self):
CM 255         cls = self._getTargetSubclass()
256         exc = cls()
53d11e 257         environ = _makeEnviron()
CM 258         start_response = DummyStartResponse()
259         body = list(exc(environ, start_response))[0]
4061d5 260         for header in start_response.headerlist:
BJR 261             if header[0] == 'Content-Type':
262                 self.assertEqual(header[1], 'text/plain; charset=UTF-8')
8e606d 263         self.assertFalse(b'<!-- ' in body)
99edc5 264
a66ce9 265     def test__content_type(self):
BJR 266         cls = self._getTargetSubclass()
267         exc = cls()
268         environ = _makeEnviron()
269         start_response = DummyStartResponse()
270         exc(environ, start_response)
271         for header in start_response.headerlist:
272             if header[0] == 'Content-Type':
273                 self.assertEqual(header[1], 'text/plain; charset=UTF-8')
274
d5e3a7 275     def test__content_type_default_is_html(self):
a66ce9 276         cls = self._getTargetSubclass()
BJR 277         exc = cls()
278         environ = _makeEnviron()
279         environ['HTTP_ACCEPT'] = '*/*'
280         start_response = DummyStartResponse()
281         exc(environ, start_response)
282         for header in start_response.headerlist:
283             if header[0] == 'Content-Type':
d5e3a7 284                 self.assertEqual(header[1], 'text/html; charset=UTF-8')
a66ce9 285
BJR 286     def test__content_type_text_html(self):
287         cls = self._getTargetSubclass()
288         exc = cls()
289         environ = _makeEnviron()
290         environ['HTTP_ACCEPT'] = 'text/html'
291         start_response = DummyStartResponse()
292         exc(environ, start_response)
293         for header in start_response.headerlist:
294             if header[0] == 'Content-Type':
295                 self.assertEqual(header[1], 'text/html; charset=UTF-8')
296
297     def test__content_type_application_json(self):
298         cls = self._getTargetSubclass()
299         exc = cls()
300         environ = _makeEnviron()
301         environ['HTTP_ACCEPT'] = 'application/json'
302         start_response = DummyStartResponse()
303         exc(environ, start_response)
304         for header in start_response.headerlist:
305             if header[0] == 'Content-Type':
306                 self.assertEqual(header[1], 'application/json')
307
62dbd4 308     def test__content_type_invalid(self):
BJR 309         cls = self._getTargetSubclass()
310         exc = cls()
311         environ = _makeEnviron()
312         environ['HTTP_ACCEPT'] = 'invalid'
313         start_response = DummyStartResponse()
314         exc(environ, start_response)
315         for header in start_response.headerlist:
316             if header[0] == 'Content-Type':
317                 self.assertEqual(header[1], 'text/html; charset=UTF-8')
318
b799e3 319     def test__default_app_iter_with_comment_ampersand(self):
99edc5 320         cls = self._getTargetSubclass()
CM 321         exc = cls(comment='comment & comment')
53d11e 322         environ = _makeEnviron()
b799e3 323         environ['HTTP_ACCEPT'] = 'text/html'
d0a5f0 324         start_response = DummyStartResponse()
CM 325         body = list(exc(environ, start_response))[0]
4061d5 326         for header in start_response.headerlist:
BJR 327             if header[0] == 'Content-Type':
328                 self.assertEqual(header[1], 'text/html; charset=UTF-8')
8e606d 329         self.assertTrue(b'<!-- comment &amp; comment -->' in body)
d0a5f0 330
4061d5 331     def test__default_app_iter_with_comment_html(self):
d0a5f0 332         cls = self._getTargetSubclass()
CM 333         exc = cls(comment='comment & comment')
334         environ = _makeEnviron()
335         environ['HTTP_ACCEPT'] = 'text/html'
53d11e 336         start_response = DummyStartResponse()
CM 337         body = list(exc(environ, start_response))[0]
8e606d 338         self.assertTrue(b'<!-- comment &amp; comment -->' in body)
99edc5 339
e195dc 340     def test__default_app_iter_with_comment_json(self):
BJR 341         cls = self._getTargetSubclass()
342         exc = cls(comment='comment & comment')
343         environ = _makeEnviron()
344         environ['HTTP_ACCEPT'] = 'application/json'
345         start_response = DummyStartResponse()
346         body = list(exc(environ, start_response))[0]
347         import json
0c29cf 348
e195dc 349         retval = json.loads(body.decode('UTF-8'))
BJR 350         self.assertEqual(retval['code'], '200 OK')
351         self.assertEqual(retval['title'], 'OK')
352
353     def test__default_app_iter_with_custom_json(self):
354         def json_formatter(status, body, title, environ):
0c29cf 355             return {
MM 356                 'message': body,
357                 'code': status,
358                 'title': title,
359                 'custom': environ['CUSTOM_VARIABLE'],
360             }
361
e195dc 362         cls = self._getTargetSubclass()
BJR 363         exc = cls(comment='comment', json_formatter=json_formatter)
364         environ = _makeEnviron()
365         environ['HTTP_ACCEPT'] = 'application/json'
366         environ['CUSTOM_VARIABLE'] = 'custom!'
367         start_response = DummyStartResponse()
368         body = list(exc(environ, start_response))[0]
369         import json
0c29cf 370
e195dc 371         retval = json.loads(body.decode('UTF-8'))
BJR 372         self.assertEqual(retval['code'], '200 OK')
373         self.assertEqual(retval['title'], 'OK')
374         self.assertEqual(retval['custom'], 'custom!')
375
53d11e 376     def test_custom_body_template(self):
99edc5 377         cls = self._getTargetSubclass()
53d11e 378         exc = cls(body_template='${REQUEST_METHOD}')
CM 379         environ = _makeEnviron()
380         start_response = DummyStartResponse()
381         body = list(exc(environ, start_response))[0]
8e606d 382         self.assertEqual(body, b'200 OK\n\nGET')
99edc5 383
4b3ba9 384     def test_custom_body_template_with_custom_variable_doesnt_choke(self):
CM 385         cls = self._getTargetSubclass()
386         exc = cls(body_template='${REQUEST_METHOD}')
387         environ = _makeEnviron()
0c29cf 388
4b3ba9 389         class Choke(object):
af01a5 390             def __str__(self):  # pragma no cover
c6a950 391                 raise ValueError
0c29cf 392
4b3ba9 393         environ['gardentheory.user'] = Choke()
CM 394         start_response = DummyStartResponse()
395         body = list(exc(environ, start_response))[0]
8e606d 396         self.assertEqual(body, b'200 OK\n\nGET')
4b3ba9 397
99edc5 398     def test_body_template_unicode(self):
CM 399         cls = self._getTargetSubclass()
954999 400         la = text_(b'/La Pe\xc3\xb1a', 'utf-8')
53d11e 401         environ = _makeEnviron(unicodeval=la)
CM 402         exc = cls(body_template='${unicodeval}')
403         start_response = DummyStartResponse()
404         body = list(exc(environ, start_response))[0]
8e606d 405         self.assertEqual(body, b'200 OK\n\n/La Pe\xc3\xb1a')
99edc5 406
d95a42 407     def test_allow_detail_non_str(self):
BJR 408         exc = self._makeOne(detail={'error': 'This is a test'})
409         self.assertIsInstance(exc.__str__(), string_types)
410
411
99edc5 412 class TestRenderAllExceptionsWithoutArguments(unittest.TestCase):
CM 413     def _doit(self, content_type):
414         from pyramid.httpexceptions import status_map
0c29cf 415
99edc5 416         L = []
CM 417         self.assertTrue(status_map)
418         for v in status_map.values():
53d11e 419             environ = _makeEnviron()
CM 420             start_response = DummyStartResponse()
99edc5 421             exc = v()
CM 422             exc.content_type = content_type
53d11e 423             result = list(exc(environ, start_response))[0]
99edc5 424             if exc.empty_body:
a84e17 425                 self.assertEqual(result, b'')
99edc5 426             else:
6df90b 427                 self.assertTrue(bytes_(exc.status) in result)
99edc5 428             L.append(result)
CM 429         self.assertEqual(len(L), len(status_map))
c6a950 430
99edc5 431     def test_it_plain(self):
CM 432         self._doit('text/plain')
433
434     def test_it_html(self):
435         self._doit('text/html')
436
0c29cf 437
99edc5 438 class Test_HTTPMove(unittest.TestCase):
CM 439     def _makeOne(self, *arg, **kw):
440         from pyramid.httpexceptions import _HTTPMove
0c29cf 441
99edc5 442         return _HTTPMove(*arg, **kw)
CM 443
dad215 444     def test_it_location_none_valueerrors(self):
dfbbe8 445         # Constructing a HTTPMove instance with location=None should
CM 446         # throw a ValueError from __init__ so that a more-confusing
447         # exception won't be thrown later from .prepare(environ)
448         self.assertRaises(ValueError, self._makeOne, location=None)
dad215 449
99edc5 450     def test_it_location_not_passed(self):
CM 451         exc = self._makeOne()
452         self.assertEqual(exc.location, '')
453
454     def test_it_location_passed(self):
455         exc = self._makeOne(location='foo')
456         self.assertEqual(exc.location, 'foo')
457
4275eb 458     def test_it_location_firstarg(self):
CM 459         exc = self._makeOne('foo')
460         self.assertEqual(exc.location, 'foo')
461
462     def test_it_call_with_default_body_tmpl(self):
463         exc = self._makeOne(location='foo')
464         environ = _makeEnviron()
465         start_response = DummyStartResponse()
466         app_iter = exc(environ, start_response)
0c29cf 467         self.assertEqual(
MM 468             app_iter[0],
469             (
470                 b'520 Unknown Error\n\nThe resource has been moved to foo; '
471                 b'you should be redirected automatically.\n\n'
472             ),
473         )
474
4275eb 475
99edc5 476 class TestHTTPForbidden(unittest.TestCase):
CM 477     def _makeOne(self, *arg, **kw):
478         from pyramid.httpexceptions import HTTPForbidden
0c29cf 479
99edc5 480         return HTTPForbidden(*arg, **kw)
CM 481
482     def test_it_result_not_passed(self):
483         exc = self._makeOne()
484         self.assertEqual(exc.result, None)
485
486     def test_it_result_passed(self):
487         exc = self._makeOne(result='foo')
488         self.assertEqual(exc.result, 'foo')
4275eb 489
0c29cf 490
4275eb 491 class TestHTTPMethodNotAllowed(unittest.TestCase):
CM 492     def _makeOne(self, *arg, **kw):
493         from pyramid.httpexceptions import HTTPMethodNotAllowed
0c29cf 494
4275eb 495         return HTTPMethodNotAllowed(*arg, **kw)
CM 496
497     def test_it_with_default_body_tmpl(self):
498         exc = self._makeOne()
499         environ = _makeEnviron()
500         start_response = DummyStartResponse()
501         app_iter = exc(environ, start_response)
0c29cf 502         self.assertEqual(
MM 503             app_iter[0],
504             (
505                 b'405 Method Not Allowed\n\nThe method GET is not '
506                 b'allowed for this resource. \n\n\n'
507             ),
508         )
4275eb 509
CM 510
99edc5 511 class DummyRequest(object):
CM 512     exception = None
0c29cf 513
1ffb8e 514
53d11e 515 class DummyStartResponse(object):
CM 516     def __call__(self, status, headerlist):
517         self.status = status
518         self.headerlist = headerlist
c6a950 519
0c29cf 520
53d11e 521 def _makeEnviron(**kw):
0c29cf 522     environ = {
MM 523         'REQUEST_METHOD': 'GET',
524         'wsgi.url_scheme': 'http',
525         'SERVER_NAME': 'localhost',
526         'SERVER_PORT': '80',
527     }
53d11e 528     environ.update(kw)
CM 529     return environ