Michael Merickel
2018-10-15 0c29cf2df41600d3906d521c72991c7686018b71
commit | author | age
c73eb9 1 from collections import deque
77a146 2 import unittest
e16ab0 3 from pyramid import testing
77a146 4
0c29cf 5 from pyramid.compat import PY2, text_, bytes_, native_
MM 6 from pyramid.security import AuthenticationAPIMixin, AuthorizationAPIMixin
7
e6c2d2 8
11644e 9 class TestRequest(unittest.TestCase):
968209 10     def setUp(self):
e16ab0 11         self.config = testing.setUp()
968209 12
CM 13     def tearDown(self):
f426e5 14         testing.tearDown()
51c305 15
11644e 16     def _getTargetClass(self):
b60bdb 17         from pyramid.request import Request
0c29cf 18
11644e 19         return Request
02ce7d 20
TS 21     def _makeOne(self, environ=None):
22         if environ is None:
23             environ = {}
24         return self._getTargetClass()(environ)
2d5424 25
c51896 26     def _registerResourceURL(self):
CM 27         from pyramid.interfaces import IResourceURL
4eafaa 28         from zope.interface import Interface
0c29cf 29
c51896 30         class DummyResourceURL(object):
4eafaa 31             def __init__(self, context, request):
c51896 32                 self.physical_path = '/context/'
CM 33                 self.virtual_path = '/context/'
0c29cf 34
4eafaa 35         self.config.registry.registerAdapter(
0c29cf 36             DummyResourceURL, (Interface, Interface), IResourceURL
MM 37         )
02ce7d 38
TS 39     def test_class_conforms_to_IRequest(self):
40         from zope.interface.verify import verifyClass
41         from pyramid.interfaces import IRequest
0c29cf 42
02ce7d 43         verifyClass(IRequest, self._getTargetClass())
TS 44
45     def test_instance_conforms_to_IRequest(self):
46         from zope.interface.verify import verifyObject
47         from pyramid.interfaces import IRequest
0c29cf 48
02ce7d 49         verifyObject(IRequest, self._makeOne())
4eafaa 50
c60c0e 51     def test_ResponseClass_is_pyramid_Response(self):
CM 52         from pyramid.response import Response
0c29cf 53
c60c0e 54         cls = self._getTargetClass()
CM 55         self.assertEqual(cls.ResponseClass, Response)
56
3c2f95 57     def test_implements_security_apis(self):
MR 58         apis = (AuthenticationAPIMixin, AuthorizationAPIMixin)
59         r = self._makeOne()
60         self.assertTrue(isinstance(r, apis))
61
2d5424 62     def test_charset_defaults_to_utf8(self):
0c29cf 63         r = self._makeOne({'PATH_INFO': '/'})
2d7993 64         self.assertEqual(r.charset, 'UTF-8')
77a146 65
81d3b5 66     def test_exception_defaults_to_None(self):
0c29cf 67         r = self._makeOne({'PATH_INFO': '/'})
81d3b5 68         self.assertEqual(r.exception, None)
51c305 69
CR 70     def test_matchdict_defaults_to_None(self):
0c29cf 71         r = self._makeOne({'PATH_INFO': '/'})
51c305 72         self.assertEqual(r.matchdict, None)
CR 73
74     def test_matched_route_defaults_to_None(self):
0c29cf 75         r = self._makeOne({'PATH_INFO': '/'})
51c305 76         self.assertEqual(r.matched_route, None)
81d3b5 77
77a146 78     def test_params_decoded_from_utf_8_by_default(self):
0c29cf 79         environ = {'PATH_INFO': '/', 'QUERY_STRING': 'la=La%20Pe%C3%B1a'}
77a146 80         request = self._makeOne(environ)
2d7993 81         request.charset = None
55fb96 82         self.assertEqual(request.GET['la'], text_(b'La Pe\xf1a'))
588c64 83
14dc81 84     def test_tmpl_context(self):
CM 85         from pyramid.request import TemplateContext
0c29cf 86
02ce7d 87         inst = self._makeOne()
14dc81 88         result = inst.tmpl_context
CM 89         self.assertEqual(result.__class__, TemplateContext)
51c305 90
968209 91     def test_session_configured(self):
CM 92         from pyramid.interfaces import ISessionFactory
0c29cf 93
02ce7d 94         inst = self._makeOne()
0c29cf 95
968209 96         def factory(request):
CM 97             return 'orangejuice'
0c29cf 98
968209 99         self.config.registry.registerUtility(factory, ISessionFactory)
CM 100         inst.registry = self.config.registry
101         self.assertEqual(inst.session, 'orangejuice')
102         self.assertEqual(inst.__dict__['session'], 'orangejuice')
103
104     def test_session_not_configured(self):
02ce7d 105         inst = self._makeOne()
968209 106         inst.registry = self.config.registry
147567 107         self.assertRaises(AttributeError, getattr, inst, 'session')
968209 108
e49bea 109     def test_setattr_and_getattr_dotnotation(self):
02ce7d 110         inst = self._makeOne()
e49bea 111         inst.foo = 1
CM 112         self.assertEqual(inst.foo, 1)
113
114     def test_setattr_and_getattr(self):
bca03f 115         environ = {}
CM 116         inst = self._makeOne(environ)
e49bea 117         setattr(inst, 'bar', 1)
CM 118         self.assertEqual(getattr(inst, 'bar'), 1)
0c29cf 119         self.assertEqual(environ, {})  # make sure we're not using adhoc attrs
11644e 120
844e98 121     def test_add_response_callback(self):
02ce7d 122         inst = self._makeOne()
37f3ed 123         self.assertEqual(len(inst.response_callbacks), 0)
0c29cf 124
844e98 125         def callback(request, response):
CM 126             """ """
0c29cf 127
844e98 128         inst.add_response_callback(callback)
c73eb9 129         self.assertEqual(list(inst.response_callbacks), [callback])
844e98 130         inst.add_response_callback(callback)
c73eb9 131         self.assertEqual(list(inst.response_callbacks), [callback, callback])
844e98 132
CM 133     def test__process_response_callbacks(self):
02ce7d 134         inst = self._makeOne()
0c29cf 135
844e98 136         def callback1(request, response):
CM 137             request.called1 = True
138             response.called1 = True
0c29cf 139
844e98 140         def callback2(request, response):
0c29cf 141             request.called2 = True
844e98 142             response.called2 = True
0c29cf 143
c73eb9 144         inst.add_response_callback(callback1)
DV 145         inst.add_response_callback(callback2)
844e98 146         response = DummyResponse()
CM 147         inst._process_response_callbacks(response)
148         self.assertEqual(inst.called1, True)
149         self.assertEqual(inst.called2, True)
150         self.assertEqual(response.called1, True)
151         self.assertEqual(response.called2, True)
c73eb9 152         self.assertEqual(len(inst.response_callbacks), 0)
844e98 153
63e6e1 154     def test__process_response_callback_adding_response_callback(self):
DV 155         """
156         When a response callback adds another callback, that new callback should still be called.
157
158         See https://github.com/Pylons/pyramid/pull/1373
159         """
160         inst = self._makeOne()
0c29cf 161
63e6e1 162         def callback1(request, response):
DV 163             request.called1 = True
164             response.called1 = True
165             request.add_response_callback(callback2)
0c29cf 166
63e6e1 167         def callback2(request, response):
0c29cf 168             request.called2 = True
63e6e1 169             response.called2 = True
0c29cf 170
63e6e1 171         inst.add_response_callback(callback1)
DV 172         response = DummyResponse()
173         inst._process_response_callbacks(response)
174         self.assertEqual(inst.called1, True)
175         self.assertEqual(inst.called2, True)
176         self.assertEqual(response.called1, True)
177         self.assertEqual(response.called2, True)
c73eb9 178         self.assertEqual(len(inst.response_callbacks), 0)
63e6e1 179
ad6a67 180     def test_add_finished_callback(self):
02ce7d 181         inst = self._makeOne()
37f3ed 182         self.assertEqual(len(inst.finished_callbacks), 0)
0c29cf 183
ad6a67 184         def callback(request):
CM 185             """ """
0c29cf 186
ad6a67 187         inst.add_finished_callback(callback)
c73eb9 188         self.assertEqual(list(inst.finished_callbacks), [callback])
ad6a67 189         inst.add_finished_callback(callback)
c73eb9 190         self.assertEqual(list(inst.finished_callbacks), [callback, callback])
ad6a67 191
CM 192     def test__process_finished_callbacks(self):
02ce7d 193         inst = self._makeOne()
0c29cf 194
ad6a67 195         def callback1(request):
CM 196             request.called1 = True
0c29cf 197
ad6a67 198         def callback2(request):
0c29cf 199             request.called2 = True
MM 200
c73eb9 201         inst.add_finished_callback(callback1)
DV 202         inst.add_finished_callback(callback2)
ad6a67 203         inst._process_finished_callbacks()
CM 204         self.assertEqual(inst.called1, True)
205         self.assertEqual(inst.called2, True)
c73eb9 206         self.assertEqual(len(inst.finished_callbacks), 0)
ad6a67 207
92c3e5 208     def test_resource_url(self):
c51896 209         self._registerResourceURL()
CM 210         environ = {
0c29cf 211             'PATH_INFO': '/',
MM 212             'SERVER_NAME': 'example.com',
213             'SERVER_PORT': '80',
214             'wsgi.url_scheme': 'http',
215         }
c51896 216         inst = self._makeOne(environ)
4eafaa 217         root = DummyContext()
92c3e5 218         result = inst.resource_url(root)
4eafaa 219         self.assertEqual(result, 'http://example.com/context/')
CM 220
221     def test_route_url(self):
222         environ = {
0c29cf 223             'PATH_INFO': '/',
MM 224             'SERVER_NAME': 'example.com',
225             'SERVER_PORT': '5432',
226             'QUERY_STRING': 'la=La%20Pe%C3%B1a',
227             'wsgi.url_scheme': 'http',
228         }
4eafaa 229         from pyramid.interfaces import IRoutesMapper
0c29cf 230
4eafaa 231         inst = self._makeOne(environ)
CM 232         mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
233         self.config.registry.registerUtility(mapper, IRoutesMapper)
0c29cf 234         result = inst.route_url(
MM 235             'flub',
236             'extra1',
237             'extra2',
238             a=1,
239             b=2,
240             c=3,
241             _query={'a': 1},
242             _anchor=text_("foo"),
243         )
244         self.assertEqual(
245             result, 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo'
246         )
4eafaa 247
2c9d14 248     def test_route_path(self):
CM 249         environ = {
0c29cf 250             'PATH_INFO': '/',
MM 251             'SERVER_NAME': 'example.com',
252             'SERVER_PORT': '5432',
253             'QUERY_STRING': 'la=La%20Pe%C3%B1a',
254             'wsgi.url_scheme': 'http',
255         }
2c9d14 256         from pyramid.interfaces import IRoutesMapper
0c29cf 257
2c9d14 258         inst = self._makeOne(environ)
CM 259         mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
260         self.config.registry.registerUtility(mapper, IRoutesMapper)
0c29cf 261         result = inst.route_path(
MM 262             'flub',
263             'extra1',
264             'extra2',
265             a=1,
266             b=2,
267             c=3,
268             _query={'a': 1},
269             _anchor=text_("foo"),
270         )
2c9d14 271         self.assertEqual(result, '/1/2/3/extra1/extra2?a=1#foo')
CM 272
9e2e1c 273     def test_static_url(self):
CM 274         from pyramid.interfaces import IStaticURLInfo
0c29cf 275
9e2e1c 276         environ = {
0c29cf 277             'PATH_INFO': '/',
MM 278             'SERVER_NAME': 'example.com',
279             'SERVER_PORT': '5432',
280             'QUERY_STRING': '',
281             'wsgi.url_scheme': 'http',
282         }
9e2e1c 283         request = self._makeOne(environ)
CM 284         info = DummyStaticURLInfo('abc')
285         self.config.registry.registerUtility(info, IStaticURLInfo)
286         result = request.static_url('pyramid.tests:static/foo.css')
287         self.assertEqual(result, 'abc')
0c29cf 288         self.assertEqual(
MM 289             info.args, ('pyramid.tests:static/foo.css', request, {})
290         )
920990 291
CM 292     def test_is_response_false(self):
02ce7d 293         request = self._makeOne()
920990 294         request.registry = self.config.registry
CM 295         self.assertEqual(request.is_response('abc'), False)
296
71cd93 297     def test_is_response_true_ob_is_pyramid_response(self):
CM 298         from pyramid.response import Response
0c29cf 299
71cd93 300         r = Response('hello')
CM 301         request = self._makeOne()
302         request.registry = self.config.registry
303         self.assertEqual(request.is_response(r), True)
304
920990 305     def test_is_response_false_adapter_is_not_self(self):
CM 306         from pyramid.interfaces import IResponse
0c29cf 307
02ce7d 308         request = self._makeOne()
920990 309         request.registry = self.config.registry
0c29cf 310
920990 311         def adapter(ob):
CM 312             return object()
0c29cf 313
920990 314         class Foo(object):
CM 315             pass
0c29cf 316
920990 317         foo = Foo()
CM 318         request.registry.registerAdapter(adapter, (Foo,), IResponse)
319         self.assertEqual(request.is_response(foo), False)
0c29cf 320
920990 321     def test_is_response_adapter_true(self):
CM 322         from pyramid.interfaces import IResponse
0c29cf 323
02ce7d 324         request = self._makeOne()
920990 325         request.registry = self.config.registry
0c29cf 326
920990 327         class Foo(object):
CM 328             pass
0c29cf 329
920990 330         foo = Foo()
0c29cf 331
920990 332         def adapter(ob):
CM 333             return ob
0c29cf 334
920990 335         request.registry.registerAdapter(adapter, (Foo,), IResponse)
CM 336         self.assertEqual(request.is_response(foo), True)
9e2e1c 337
6a0602 338     def test_json_body_invalid_json(self):
0c29cf 339         request = self._makeOne({'REQUEST_METHOD': 'POST'})
8e606d 340         request.body = b'{'
6a0602 341         self.assertRaises(ValueError, getattr, request, 'json_body')
0c29cf 342
6a0602 343     def test_json_body_valid_json(self):
0c29cf 344         request = self._makeOne({'REQUEST_METHOD': 'POST'})
8e606d 345         request.body = b'{"a":1}'
0c29cf 346         self.assertEqual(request.json_body, {'a': 1})
b78eff 347
6a0602 348     def test_json_body_alternate_charset(self):
5cf9fc 349         import json
0c29cf 350
MM 351         request = self._makeOne({'REQUEST_METHOD': 'POST'})
632a91 352         inp = text_(
0c29cf 353             b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8'
MM 354         )
bc37a5 355         if PY2:
0c29cf 356             body = json.dumps({'a': inp}).decode('utf-8').encode('utf-16')
bc37a5 357         else:
0c29cf 358             body = bytes(json.dumps({'a': inp}), 'utf-16')
b78eff 359         request.body = body
632a91 360         request.content_type = 'application/json; charset=utf-16'
0c29cf 361         self.assertEqual(request.json_body, {'a': inp})
6a0602 362
CM 363     def test_json_body_GET_request(self):
0c29cf 364         request = self._makeOne({'REQUEST_METHOD': 'GET'})
6a0602 365         self.assertRaises(ValueError, getattr, request, 'json_body')
b78eff 366
577db9 367     def test_set_property(self):
02ce7d 368         request = self._makeOne()
577db9 369         opts = [2, 1]
0c29cf 370
577db9 371         def connect(obj):
MM 372             return opts.pop()
0c29cf 373
577db9 374         request.set_property(connect, name='db')
MM 375         self.assertEqual(1, request.db)
376         self.assertEqual(2, request.db)
377
378     def test_set_property_reify(self):
02ce7d 379         request = self._makeOne()
577db9 380         opts = [2, 1]
0c29cf 381
577db9 382         def connect(obj):
MM 383             return opts.pop()
0c29cf 384
577db9 385         request.set_property(connect, name='db', reify=True)
MM 386         self.assertEqual(1, request.db)
387         self.assertEqual(1, request.db)
388
0c29cf 389
11644e 390 class Test_route_request_iface(unittest.TestCase):
dfc2b6 391     def _callFUT(self, name):
b60bdb 392         from pyramid.request import route_request_iface
0c29cf 393
11644e 394         return route_request_iface(name)
dfc2b6 395
CM 396     def test_it(self):
11644e 397         iface = self._callFUT('routename')
de8212 398         self.assertEqual(iface.__name__, 'routename_IRequest')
ff1213 399         self.assertTrue(hasattr(iface, 'combined'))
0c29cf 400         self.assertEqual(
MM 401             iface.combined.__name__, 'routename_combined_IRequest'
402         )
dfc2b6 403
873d9b 404     def test_it_routename_with_spaces(self):
CM 405         #  see https://github.com/Pylons/pyramid/issues/232
406         iface = self._callFUT('routename with spaces')
407         self.assertEqual(iface.__name__, 'routename with spaces_IRequest')
408         self.assertTrue(hasattr(iface, 'combined'))
0c29cf 409         self.assertEqual(
MM 410             iface.combined.__name__, 'routename with spaces_combined_IRequest'
411         )
412
873d9b 413
839ea0 414 class Test_add_global_response_headers(unittest.TestCase):
CM 415     def _callFUT(self, request, headerlist):
b60bdb 416         from pyramid.request import add_global_response_headers
0c29cf 417
839ea0 418         return add_global_response_headers(request, headerlist)
CM 419
164677 420     def test_it(self):
839ea0 421         request = DummyRequest()
844e98 422         response = DummyResponse()
839ea0 423         self._callFUT(request, [('c', 1)])
844e98 424         self.assertEqual(len(request.response_callbacks), 1)
CM 425         request.response_callbacks[0](None, response)
0c29cf 426         self.assertEqual(response.headerlist, [('c', 1)])
MM 427
839ea0 428
65a5a9 429 class Test_call_app_with_subpath_as_path_info(unittest.TestCase):
CM 430     def _callFUT(self, request, app):
431         from pyramid.request import call_app_with_subpath_as_path_info
0c29cf 432
65a5a9 433         return call_app_with_subpath_as_path_info(request, app)
CM 434
435     def test_it_all_request_and_environment_data_missing(self):
436         request = DummyRequest({})
437         response = self._callFUT(request, 'app')
438         self.assertTrue(request.copied)
439         self.assertEqual(response, 'app')
440         self.assertEqual(request.environ['SCRIPT_NAME'], '')
441         self.assertEqual(request.environ['PATH_INFO'], '/')
442
443     def test_it_with_subpath_and_path_info(self):
0c29cf 444         request = DummyRequest({'PATH_INFO': '/hello'})
65a5a9 445         request.subpath = ('hello',)
CM 446         response = self._callFUT(request, 'app')
447         self.assertTrue(request.copied)
448         self.assertEqual(response, 'app')
449         self.assertEqual(request.environ['SCRIPT_NAME'], '')
450         self.assertEqual(request.environ['PATH_INFO'], '/hello')
451
452     def test_it_with_subpath_and_path_info_path_info_endswith_slash(self):
0c29cf 453         request = DummyRequest({'PATH_INFO': '/hello/'})
65a5a9 454         request.subpath = ('hello',)
CM 455         response = self._callFUT(request, 'app')
456         self.assertTrue(request.copied)
457         self.assertEqual(response, 'app')
458         self.assertEqual(request.environ['SCRIPT_NAME'], '')
459         self.assertEqual(request.environ['PATH_INFO'], '/hello/')
460
461     def test_it_with_subpath_and_path_info_extra_script_name(self):
0c29cf 462         request = DummyRequest(
MM 463             {'PATH_INFO': '/hello', 'SCRIPT_NAME': '/script'}
464         )
65a5a9 465         request.subpath = ('hello',)
CM 466         response = self._callFUT(request, 'app')
467         self.assertTrue(request.copied)
468         self.assertEqual(response, 'app')
469         self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
470         self.assertEqual(request.environ['PATH_INFO'], '/hello')
471
472     def test_it_with_extra_slashes_in_path_info(self):
0c29cf 473         request = DummyRequest(
MM 474             {'PATH_INFO': '//hello/', 'SCRIPT_NAME': '/script'}
475         )
65a5a9 476         request.subpath = ('hello',)
CM 477         response = self._callFUT(request, 'app')
478         self.assertTrue(request.copied)
479         self.assertEqual(response, 'app')
480         self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
481         self.assertEqual(request.environ['PATH_INFO'], '/hello/')
482
483     def test_subpath_path_info_and_script_name_have_utf8(self):
c779f1 484         encoded = native_(text_(b'La Pe\xc3\xb1a'))
CM 485         decoded = text_(bytes_(encoded), 'utf-8')
0c29cf 486         request = DummyRequest(
MM 487             {'PATH_INFO': '/' + encoded, 'SCRIPT_NAME': '/' + encoded}
488         )
489         request.subpath = (decoded,)
65a5a9 490         response = self._callFUT(request, 'app')
CM 491         self.assertTrue(request.copied)
492         self.assertEqual(response, 'app')
c779f1 493         self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded)
CM 494         self.assertEqual(request.environ['PATH_INFO'], '/' + encoded)
0c29cf 495
65a5a9 496
04cc91 497 class Test_apply_request_extensions(unittest.TestCase):
MM 498     def setUp(self):
499         self.config = testing.setUp()
500
501     def tearDown(self):
502         testing.tearDown()
503
504     def _callFUT(self, request, extensions=None):
505         from pyramid.request import apply_request_extensions
0c29cf 506
04cc91 507         return apply_request_extensions(request, extensions=extensions)
MM 508
509     def test_it_with_registry(self):
510         from pyramid.interfaces import IRequestExtensions
0c29cf 511
04cc91 512         extensions = Dummy()
MM 513         extensions.methods = {'foo': lambda x, y: y}
514         extensions.descriptors = {'bar': property(lambda x: 'bar')}
515         self.config.registry.registerUtility(extensions, IRequestExtensions)
516         request = DummyRequest()
517         request.registry = self.config.registry
518         self._callFUT(request)
519         self.assertEqual(request.bar, 'bar')
520         self.assertEqual(request.foo('abc'), 'abc')
521
522     def test_it_override_extensions(self):
523         from pyramid.interfaces import IRequestExtensions
0c29cf 524
04cc91 525         ignore = Dummy()
MM 526         ignore.methods = {'x': lambda x, y, z: 'asdf'}
527         ignore.descriptors = {'bar': property(lambda x: 'asdf')}
528         self.config.registry.registerUtility(ignore, IRequestExtensions)
529         request = DummyRequest()
530         request.registry = self.config.registry
531
532         extensions = Dummy()
533         extensions.methods = {'foo': lambda x, y: y}
534         extensions.descriptors = {'bar': property(lambda x: 'bar')}
535         self._callFUT(request, extensions=extensions)
536         self.assertRaises(AttributeError, lambda: request.x)
537         self.assertEqual(request.bar, 'bar')
538         self.assertEqual(request.foo('abc'), 'abc')
539
0c29cf 540
04cc91 541 class Dummy(object):
MM 542     pass
0c29cf 543
04cc91 544
697213 545 class Test_subclassing_Request(unittest.TestCase):
BJR 546     def test_subclass(self):
942e7d 547         from pyramid.interfaces import IRequest
697213 548         from pyramid.request import Request
BJR 549
550         class RequestSub(Request):
551             pass
552
553         self.assertTrue(hasattr(Request, '__provides__'))
942e7d 554         self.assertTrue(hasattr(Request, '__implemented__'))
BJR 555         self.assertTrue(hasattr(Request, '__providedBy__'))
697213 556         self.assertFalse(hasattr(RequestSub, '__provides__'))
942e7d 557         self.assertTrue(hasattr(RequestSub, '__providedBy__'))
BJR 558         self.assertTrue(hasattr(RequestSub, '__implemented__'))
559
560         self.assertTrue(IRequest.implementedBy(RequestSub))
561         # The call to implementedBy will add __provides__ to the class
562         self.assertTrue(hasattr(RequestSub, '__provides__'))
697213 563
BJR 564     def test_subclass_with_implementer(self):
565         from pyramid.interfaces import IRequest
566         from pyramid.request import Request
d7734b 567         from pyramid.util import InstancePropertyHelper
CM 568         from zope.interface import implementer
697213 569
BJR 570         @implementer(IRequest)
571         class RequestSub(Request):
572             pass
573
574         self.assertTrue(hasattr(Request, '__provides__'))
942e7d 575         self.assertTrue(hasattr(Request, '__implemented__'))
BJR 576         self.assertTrue(hasattr(Request, '__providedBy__'))
697213 577         self.assertTrue(hasattr(RequestSub, '__provides__'))
942e7d 578         self.assertTrue(hasattr(RequestSub, '__providedBy__'))
BJR 579         self.assertTrue(hasattr(RequestSub, '__implemented__'))
697213 580
BJR 581         req = RequestSub({})
d7734b 582         helper = InstancePropertyHelper()
CM 583         helper.apply_properties(req, {'b': 'b'})
942e7d 584
BJR 585         self.assertTrue(IRequest.providedBy(req))
586         self.assertTrue(IRequest.implementedBy(RequestSub))
587
c7c02f 588     def test_subclass_mutate_before_providedBy(self):
BJR 589         from pyramid.interfaces import IRequest
590         from pyramid.request import Request
d7734b 591         from pyramid.util import InstancePropertyHelper
c7c02f 592
BJR 593         class RequestSub(Request):
594             pass
595
596         req = RequestSub({})
d7734b 597         helper = InstancePropertyHelper()
CM 598         helper.apply_properties(req, {'b': 'b'})
c7c02f 599
BJR 600         self.assertTrue(IRequest.providedBy(req))
601         self.assertTrue(IRequest.implementedBy(RequestSub))
602
697213 603
04cc91 604 class DummyRequest(object):
d66bfb 605     def __init__(self, environ=None):
CM 606         if environ is None:
607             environ = {}
608         self.environ = environ
77a146 609
844e98 610     def add_response_callback(self, callback):
CM 611         self.response_callbacks = [callback]
612
65a5a9 613     def get_response(self, app):
CM 614         return app
615
616     def copy(self):
617         self.copied = True
618         return self
619
0c29cf 620
844e98 621 class DummyResponse:
CM 622     def __init__(self):
a58c4a 623         self.headerlist = []
77a146 624
CM 625
4eafaa 626 class DummyContext:
CM 627     pass
628
0c29cf 629
4eafaa 630 class DummyRoutesMapper:
CM 631     raise_exc = None
0c29cf 632
4eafaa 633     def __init__(self, route=None, raise_exc=False):
CM 634         self.route = route
635
636     def get_route(self, route_name):
637         return self.route
638
0c29cf 639
4eafaa 640 class DummyRoute:
CM 641     pregenerator = None
0c29cf 642
4eafaa 643     def __init__(self, result='/1/2/3'):
CM 644         self.result = result
645
646     def generate(self, kw):
647         self.kw = kw
648         return self.result
9e2e1c 649
0c29cf 650
9e2e1c 651 class DummyStaticURLInfo:
CM 652     def __init__(self, result):
653         self.result = result
654
655     def generate(self, path, request, **kw):
656         self.args = path, request, kw
657         return self.result