Michael Merickel
2017-07-08 0109711792b0735488342b7e3efe4ee1fb303dbd
commit | author | age
7e2c6c 1 import unittest
e6fa66 2 import sys
7e2c6c 3
3b7334 4 from zope.interface import implementer
CM 5
a00621 6 from pyramid import testing
7e2c6c 7
849196 8 from pyramid.interfaces import IRequest
CM 9
d20d09 10 class BaseTest(object):
7e2c6c 11     def setUp(self):
a00621 12         self.config = testing.setUp()
7e2c6c 13
CM 14     def tearDown(self):
a00621 15         testing.tearDown()
7e2c6c 16
333bd0 17     def _registerView(self, reg, app, name):
b60bdb 18         from pyramid.interfaces import IViewClassifier
ff1213 19         for_ = (IViewClassifier, IRequest, IContext)
b60bdb 20         from pyramid.interfaces import IView
1c0210 21         reg.registerAdapter(app, for_, IView, name)
7e2c6c 22
CM 23     def _makeEnviron(self, **extras):
24         environ = {
25             'wsgi.url_scheme':'http',
d20d09 26             'wsgi.version':(1,0),
7e2c6c 27             'SERVER_NAME':'localhost',
CM 28             'SERVER_PORT':'8080',
29             'REQUEST_METHOD':'GET',
b596e1 30             'PATH_INFO':'/',
7e2c6c 31             }
CM 32         environ.update(extras)
33         return environ
34
1c0210 35     def _makeRequest(self, **environ):
849196 36         from pyramid.request import Request
b60bdb 37         from pyramid.registry import Registry
1c0210 38         environ = self._makeEnviron(**environ)
CM 39         request = Request(environ)
40         request.registry = Registry()
41         return request
42
43     def _makeContext(self):
44         from zope.interface import directlyProvides
45         context = DummyContext()
46         directlyProvides(context, IContext)
47         return context
0db4a1 48
CM 49 class Test_notfound_view_config(BaseTest, unittest.TestCase):
50     def _makeOne(self, **kw):
51         from pyramid.view import notfound_view_config
52         return notfound_view_config(**kw)
53
54     def test_ctor(self):
55         inst = self._makeOne(attr='attr', path_info='path_info', 
56                              append_slash=True)
57         self.assertEqual(inst.__dict__,
58                          {'attr':'attr', 'path_info':'path_info',
59                           'append_slash':True})
60
61     def test_it_function(self):
62         def view(request): pass
63         decorator = self._makeOne(attr='attr', renderer='renderer',
64                                   append_slash=True)
65         venusian = DummyVenusian()
66         decorator.venusian = venusian
67         wrapped = decorator(view)
68         self.assertTrue(wrapped is view)
69         config = call_venusian(venusian)
70         settings = config.settings
71         self.assertEqual(
72             settings, 
73             [{'attr': 'attr', 'venusian': venusian, 'append_slash': True, 
74               'renderer': 'renderer', '_info': 'codeinfo', 'view': None}]
75             )
76
77     def test_it_class(self):
78         decorator = self._makeOne()
79         venusian = DummyVenusian()
80         decorator.venusian = venusian
81         decorator.venusian.info.scope = 'class'
82         class view(object): pass
83         wrapped = decorator(view)
84         self.assertTrue(wrapped is view)
85         config = call_venusian(venusian)
86         settings = config.settings
87         self.assertEqual(len(settings), 1)
8ec8e2 88         self.assertEqual(len(settings[0]), 4)
0db4a1 89         self.assertEqual(settings[0]['venusian'], venusian)
CM 90         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
91         self.assertEqual(settings[0]['attr'], 'view')
92         self.assertEqual(settings[0]['_info'], 'codeinfo')
1c0210 93
010971 94     def test_call_with_venusian_args(self):
MM 95         decorator = self._makeOne(_depth=1, _category='foo')
96         venusian = DummyVenusian()
97         decorator.venusian = venusian
98         def foo(): pass
99         decorator(foo)
100         attachments = venusian.attachments
101         category = attachments[0][2]
102         depth = attachments[0][3]
103         self.assertEqual(depth, 2)
104         self.assertEqual(category, 'foo')
105
a7fe30 106 class Test_forbidden_view_config(BaseTest, unittest.TestCase):
CM 107     def _makeOne(self, **kw):
108         from pyramid.view import forbidden_view_config
109         return forbidden_view_config(**kw)
110
111     def test_ctor(self):
112         inst = self._makeOne(attr='attr', path_info='path_info')
113         self.assertEqual(inst.__dict__,
114                          {'attr':'attr', 'path_info':'path_info'})
115
116     def test_it_function(self):
117         def view(request): pass
118         decorator = self._makeOne(attr='attr', renderer='renderer')
119         venusian = DummyVenusian()
120         decorator.venusian = venusian
121         wrapped = decorator(view)
122         self.assertTrue(wrapped is view)
123         config = call_venusian(venusian)
124         settings = config.settings
125         self.assertEqual(
126             settings, 
127             [{'attr': 'attr', 'venusian': venusian, 
128               'renderer': 'renderer', '_info': 'codeinfo', 'view': None}]
129             )
130
131     def test_it_class(self):
132         decorator = self._makeOne()
133         venusian = DummyVenusian()
134         decorator.venusian = venusian
135         decorator.venusian.info.scope = 'class'
136         class view(object): pass
137         wrapped = decorator(view)
138         self.assertTrue(wrapped is view)
139         config = call_venusian(venusian)
140         settings = config.settings
141         self.assertEqual(len(settings), 1)
142         self.assertEqual(len(settings[0]), 4)
143         self.assertEqual(settings[0]['venusian'], venusian)
144         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
145         self.assertEqual(settings[0]['attr'], 'view')
146         self.assertEqual(settings[0]['_info'], 'codeinfo')
010971 147
MM 148     def test_call_with_venusian_args(self):
149         decorator = self._makeOne(_depth=1, _category='foo')
150         venusian = DummyVenusian()
151         decorator.venusian = venusian
152         def foo(): pass
153         decorator(foo)
154         attachments = venusian.attachments
155         category = attachments[0][2]
156         depth = attachments[0][3]
157         self.assertEqual(depth, 2)
158         self.assertEqual(category, 'foo')
93c94b 159
AL 160 class Test_exception_view_config(BaseTest, unittest.TestCase):
e8c66a 161     def _makeOne(self, *args, **kw):
93c94b 162         from pyramid.view import exception_view_config
e8c66a 163         return exception_view_config(*args, **kw)
93c94b 164
AL 165     def test_ctor(self):
166         inst = self._makeOne(context=Exception, path_info='path_info')
167         self.assertEqual(inst.__dict__,
168                          {'context':Exception, 'path_info':'path_info'})
169
e8c66a 170     def test_ctor_positional_exception(self):
MM 171         inst = self._makeOne(Exception, path_info='path_info')
172         self.assertEqual(inst.__dict__,
173                          {'context':Exception, 'path_info':'path_info'})
174
175     def test_ctor_positional_extras(self):
176         from pyramid.exceptions import ConfigurationError
177         self.assertRaises(ConfigurationError, lambda: self._makeOne(Exception, True))
178
93c94b 179     def test_it_function(self):
AL 180         def view(request): pass
181         decorator = self._makeOne(context=Exception, renderer='renderer')
182         venusian = DummyVenusian()
183         decorator.venusian = venusian
184         wrapped = decorator(view)
185         self.assertTrue(wrapped is view)
186         config = call_venusian(venusian)
187         settings = config.settings
188         self.assertEqual(
189             settings,
190             [{'venusian': venusian, 'context': Exception,
191               'renderer': 'renderer', '_info': 'codeinfo', 'view': None}]
192             )
193
194     def test_it_class(self):
195         decorator = self._makeOne()
196         venusian = DummyVenusian()
197         decorator.venusian = venusian
198         decorator.venusian.info.scope = 'class'
199         class view(object): pass
200         wrapped = decorator(view)
201         self.assertTrue(wrapped is view)
202         config = call_venusian(venusian)
203         settings = config.settings
204         self.assertEqual(len(settings), 1)
205         self.assertEqual(len(settings[0]), 4)
206         self.assertEqual(settings[0]['venusian'], venusian)
207         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
208         self.assertEqual(settings[0]['attr'], 'view')
209         self.assertEqual(settings[0]['_info'], 'codeinfo')
010971 210
MM 211     def test_call_with_venusian_args(self):
212         decorator = self._makeOne(_depth=1, _category='foo')
213         venusian = DummyVenusian()
214         decorator.venusian = venusian
215         def foo(): pass
216         decorator(foo)
217         attachments = venusian.attachments
218         category = attachments[0][2]
219         depth = attachments[0][3]
220         self.assertEqual(depth, 2)
221         self.assertEqual(category, 'foo')
93c94b 222
d1c4f0 223 class RenderViewToResponseTests(BaseTest, unittest.TestCase):
b3d74b 224     def _callFUT(self, *arg, **kw):
b60bdb 225         from pyramid.view import render_view_to_response
b3d74b 226         return render_view_to_response(*arg, **kw)
7e2c6c 227     
CM 228     def test_call_no_view_registered(self):
1c0210 229         request = self._makeRequest()
CM 230         context = self._makeContext()
b3d74b 231         result = self._callFUT(context, request, name='notregistered')
7e2c6c 232         self.assertEqual(result, None)
CM 233
45d08c 234     def test_call_no_registry_on_request(self):
CM 235         request = self._makeRequest()
236         del request.registry
237         context = self._makeContext()
238         result = self._callFUT(context, request, name='notregistered')
239         self.assertEqual(result, None)
240
d66bfb 241     def test_call_view_registered_secure(self):
1c0210 242         request = self._makeRequest()
CM 243         context = self._makeContext()
7e2c6c 244         response = DummyResponse()
CM 245         view = make_view(response)
1c0210 246         self._registerView(request.registry, view, 'registered')
b3d74b 247         response = self._callFUT(context, request, name='registered',
CM 248                                  secure=True)
7e2c6c 249         self.assertEqual(response.status, '200 OK')
CM 250
d66bfb 251     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 252         context = self._makeContext()
CM 253         request = self._makeRequest()
7e2c6c 254         response = DummyResponse()
CM 255         view = make_view(response)
1c0210 256         self._registerView(request.registry, view, 'registered')
b3d74b 257         response = self._callFUT(context, request, name='registered',
CM 258                                  secure=False)
7e2c6c 259         self.assertEqual(response.status, '200 OK')
d66bfb 260
CM 261     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 262         context = self._makeContext()
CM 263         request = self._makeRequest()
d66bfb 264         response = DummyResponse()
CM 265         view = make_view(response)
266         def anotherview(context, request):
267             return DummyResponse('anotherview')
268         view.__call_permissive__ = anotherview
1c0210 269         self._registerView(request.registry, view, 'registered')
d66bfb 270         response = self._callFUT(context, request, name='registered',
CM 271                                  secure=False)
272         self.assertEqual(response.status, '200 OK')
273         self.assertEqual(response.app_iter, ['anotherview'])
7e2c6c 274
713bc5 275     def test_call_view_with_request_iface_on_request(self):
CM 276         # See https://github.com/Pylons/pyramid/issues/1643
277         from zope.interface import Interface
278         class IWontBeFound(Interface): pass
279         context = self._makeContext()
280         request = self._makeRequest()
281         request.request_iface = IWontBeFound
282         response = DummyResponse('aview')
283         view = make_view(response)
284         self._registerView(request.registry, view, 'aview')
285         response = self._callFUT(context, request, name='aview')
286         self.assertEqual(response.status, '200 OK')
287         self.assertEqual(response.app_iter, ['aview'])
288
d1c4f0 289 class RenderViewToIterableTests(BaseTest, unittest.TestCase):
b3d74b 290     def _callFUT(self, *arg, **kw):
b60bdb 291         from pyramid.view import render_view_to_iterable
b3d74b 292         return render_view_to_iterable(*arg, **kw)
7e2c6c 293     
CM 294     def test_call_no_view_registered(self):
1c0210 295         request = self._makeRequest()
CM 296         context = self._makeContext()
b3d74b 297         result = self._callFUT(context, request, name='notregistered')
7e2c6c 298         self.assertEqual(result, None)
CM 299
d66bfb 300     def test_call_view_registered_secure(self):
1c0210 301         request = self._makeRequest()
CM 302         context = self._makeContext()
7e2c6c 303         response = DummyResponse()
CM 304         view = make_view(response)
1c0210 305         self._registerView(request.registry, view, 'registered')
b3d74b 306         iterable = self._callFUT(context, request, name='registered',
CM 307                                  secure=True)
7e2c6c 308         self.assertEqual(iterable, ())
CM 309
d66bfb 310     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 311         context = self._makeContext()
CM 312         request = self._makeRequest()
7e2c6c 313         response = DummyResponse()
CM 314         view = make_view(response)
1c0210 315         self._registerView(request.registry, view, 'registered')
b3d74b 316         iterable = self._callFUT(context, request, name='registered',
CM 317                                  secure=False)
7e2c6c 318         self.assertEqual(iterable, ())
d66bfb 319
CM 320     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 321         context = self._makeContext()
CM 322         request = self._makeRequest()
d66bfb 323         response = DummyResponse()
CM 324         view = make_view(response)
325         def anotherview(context, request):
0a8ea9 326             return DummyResponse(b'anotherview')
d66bfb 327         view.__call_permissive__ = anotherview
1c0210 328         self._registerView(request.registry, view, 'registered')
d66bfb 329         iterable = self._callFUT(context, request, name='registered',
CM 330                                  secure=False)
0a8ea9 331         self.assertEqual(iterable, [b'anotherview'])
MM 332
6ec5a6 333     def test_verify_output_bytestring(self):
AV 334         from pyramid.request import Request
335         from pyramid.config import Configurator
336         from pyramid.view import render_view
337         from webob.compat import text_type
338         config = Configurator(settings={})
339         def view(request):
340             request.response.text = text_type('<body></body>')
341             return request.response
342
343         config.add_view(name='test', view=view)
344         config.commit()
345
346         r = Request({})
347         r.registry = config.registry
348         self.assertEqual(render_view(object(), r, 'test'), b'<body></body>')
7e2c6c 349
08ffc9 350     def test_call_request_has_no_registry(self):
CM 351         request = self._makeRequest()
352         del request.registry
353         registry = self.config.registry
354         context = self._makeContext()
355         response = DummyResponse()
356         view = make_view(response)
357         self._registerView(registry, view, 'registered')
358         iterable = self._callFUT(context, request, name='registered',
359                                  secure=True)
360         self.assertEqual(iterable, ())
361
1c0210 362 class RenderViewTests(BaseTest, unittest.TestCase):
b3d74b 363     def _callFUT(self, *arg, **kw):
b60bdb 364         from pyramid.view import render_view
b3d74b 365         return render_view(*arg, **kw)
885bfb 366     
CM 367     def test_call_no_view_registered(self):
1c0210 368         request = self._makeRequest()
CM 369         context = self._makeContext()
b3d74b 370         result = self._callFUT(context, request, name='notregistered')
885bfb 371         self.assertEqual(result, None)
CM 372
d66bfb 373     def test_call_view_registered_secure(self):
1c0210 374         request = self._makeRequest()
CM 375         context = self._makeContext()
885bfb 376         response = DummyResponse()
CM 377         view = make_view(response)
1c0210 378         self._registerView(request.registry, view, 'registered')
b3d74b 379         s = self._callFUT(context, request, name='registered', secure=True)
6ec5a6 380         self.assertEqual(s, b'')
885bfb 381
d66bfb 382     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 383         context = self._makeContext()
CM 384         request = self._makeRequest()
885bfb 385         response = DummyResponse()
CM 386         view = make_view(response)
1c0210 387         self._registerView(request.registry, view, 'registered')
b3d74b 388         s = self._callFUT(context, request, name='registered', secure=False)
6ec5a6 389         self.assertEqual(s, b'')
d66bfb 390
CM 391     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 392         context = self._makeContext()
CM 393         request = self._makeRequest()
d66bfb 394         response = DummyResponse()
CM 395         view = make_view(response)
396         def anotherview(context, request):
0a8ea9 397             return DummyResponse(b'anotherview')
d66bfb 398         view.__call_permissive__ = anotherview
1c0210 399         self._registerView(request.registry, view, 'registered')
d66bfb 400         s = self._callFUT(context, request, name='registered', secure=False)
6ec5a6 401         self.assertEqual(s, b'anotherview')
885bfb 402
197f0c 403 class TestViewConfigDecorator(unittest.TestCase):
5a7f9a 404     def setUp(self):
a00621 405         testing.setUp()
5a7f9a 406
CM 407     def tearDown(self):
a00621 408         testing.tearDown()
5a7f9a 409
CM 410     def _getTargetClass(self):
197f0c 411         from pyramid.view import view_config
CM 412         return view_config
5a7f9a 413
CM 414     def _makeOne(self, *arg, **kw):
415         return self._getTargetClass()(*arg, **kw)
416
417     def test_create_defaults(self):
418         decorator = self._makeOne()
4c29ef 419         self.assertEqual(decorator.__dict__, {})
b04bd5 420
CM 421     def test_create_context_trumps_for(self):
422         decorator = self._makeOne(context='123', for_='456')
423         self.assertEqual(decorator.context, '123')
424
425     def test_create_for_trumps_context_None(self):
426         decorator = self._makeOne(context=None, for_='456')
427         self.assertEqual(decorator.context, '456')
5a7f9a 428         
CM 429     def test_create_nondefaults(self):
4c29ef 430         decorator = self._makeOne(
CM 431             name=None, request_type=None, for_=None,
432             permission='foo', mapper='mapper',
433             decorator='decorator', match_param='match_param'
434             )
5a7f9a 435         self.assertEqual(decorator.name, None)
CM 436         self.assertEqual(decorator.request_type, None)
eecdbc 437         self.assertEqual(decorator.context, None)
5a7f9a 438         self.assertEqual(decorator.permission, 'foo')
5e3d64 439         self.assertEqual(decorator.mapper, 'mapper')
1d9ade 440         self.assertEqual(decorator.decorator, 'decorator')
bf5e0e 441         self.assertEqual(decorator.match_param, 'match_param')
8ec8e2 442
CM 443     def test_create_with_other_predicates(self):
444         decorator = self._makeOne(foo=1)
445         self.assertEqual(decorator.foo, 1)
76c9c2 446
R 447     def test_create_decorator_tuple(self):
448         decorator = self._makeOne(decorator=('decorator1', 'decorator2'))
449         self.assertEqual(decorator.decorator, ('decorator1', 'decorator2'))
5a7f9a 450         
5a11e2 451     def test_call_function(self):
CM 452         decorator = self._makeOne()
e6fa66 453         venusian = DummyVenusian()
CM 454         decorator.venusian = venusian
455         def foo(): pass
5a11e2 456         wrapped = decorator(foo)
a1d395 457         self.assertTrue(wrapped is foo)
b2c4e0 458         config = call_venusian(venusian)
CM 459         settings = config.settings
e6fa66 460         self.assertEqual(len(settings), 1)
4c29ef 461         self.assertEqual(len(settings), 1)
CM 462         self.assertEqual(len(settings[0]), 3)
463         self.assertEqual(settings[0]['venusian'], venusian)
464         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
465         self.assertEqual(settings[0]['_info'], 'codeinfo')
5a11e2 466
e6fa66 467     def test_call_class(self):
5a7f9a 468         decorator = self._makeOne()
e6fa66 469         venusian = DummyVenusian()
CM 470         decorator.venusian = venusian
471         decorator.venusian.info.scope = 'class'
472         class foo(object): pass
5a7f9a 473         wrapped = decorator(foo)
a1d395 474         self.assertTrue(wrapped is foo)
b2c4e0 475         config = call_venusian(venusian)
CM 476         settings = config.settings
e6fa66 477         self.assertEqual(len(settings), 1)
4c29ef 478         self.assertEqual(len(settings[0]), 4)
CM 479         self.assertEqual(settings[0]['venusian'], venusian)
480         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
b04bd5 481         self.assertEqual(settings[0]['attr'], 'foo')
4c29ef 482         self.assertEqual(settings[0]['_info'], 'codeinfo')
b04bd5 483
CM 484     def test_call_class_attr_already_set(self):
485         decorator = self._makeOne(attr='abc')
486         venusian = DummyVenusian()
487         decorator.venusian = venusian
488         decorator.venusian.info.scope = 'class'
489         class foo(object): pass
490         wrapped = decorator(foo)
a1d395 491         self.assertTrue(wrapped is foo)
b2c4e0 492         config = call_venusian(venusian)
CM 493         settings = config.settings
b04bd5 494         self.assertEqual(len(settings), 1)
4c29ef 495         self.assertEqual(len(settings[0]), 4)
CM 496         self.assertEqual(settings[0]['venusian'], venusian)
497         self.assertEqual(settings[0]['view'], None) # comes from call_venusian
b04bd5 498         self.assertEqual(settings[0]['attr'], 'abc')
4c29ef 499         self.assertEqual(settings[0]['_info'], 'codeinfo')
5a7f9a 500
2cce43 501     def test_stacking(self):
CM 502         decorator1 = self._makeOne(name='1')
e6fa66 503         venusian1 = DummyVenusian()
CM 504         decorator1.venusian = venusian1
505         venusian2 = DummyVenusian()
2cce43 506         decorator2 = self._makeOne(name='2')
e6fa66 507         decorator2.venusian = venusian2
CM 508         def foo(): pass
2cce43 509         wrapped1 = decorator1(foo)
CM 510         wrapped2 = decorator2(wrapped1)
a1d395 511         self.assertTrue(wrapped1 is foo)
CM 512         self.assertTrue(wrapped2 is foo)
b2c4e0 513         config1 = call_venusian(venusian1)
CM 514         self.assertEqual(len(config1.settings), 1)
515         self.assertEqual(config1.settings[0]['name'], '1')
516         config2 = call_venusian(venusian2)
517         self.assertEqual(len(config2.settings), 1)
518         self.assertEqual(config2.settings[0]['name'], '2')
2cce43 519
b2f929 520     def test_call_as_method(self):
CM 521         decorator = self._makeOne()
e6fa66 522         venusian = DummyVenusian()
CM 523         decorator.venusian = venusian
524         decorator.venusian.info.scope = 'class'
b2f929 525         def foo(self): pass
CM 526         def bar(self): pass
527         class foo(object):
528             foomethod = decorator(foo)
529             barmethod = decorator(bar)
b2c4e0 530         config = call_venusian(venusian)
CM 531         settings = config.settings
b2f929 532         self.assertEqual(len(settings), 2)
CM 533         self.assertEqual(settings[0]['attr'], 'foo')
534         self.assertEqual(settings[1]['attr'], 'bar')
535
6225a2 536     def test_with_custom_predicates(self):
CM 537         decorator = self._makeOne(custom_predicates=(1,))
e6fa66 538         venusian = DummyVenusian()
CM 539         decorator.venusian = venusian
540         def foo(context, request): pass
6225a2 541         decorated = decorator(foo)
a1d395 542         self.assertTrue(decorated is foo)
b2c4e0 543         config = call_venusian(venusian)
CM 544         settings = config.settings
6225a2 545         self.assertEqual(settings[0]['custom_predicates'], (1,))
CM 546
3d9dd0 547     def test_call_with_renderer_string(self):
CM 548         import pyramid.tests
89968d 549         decorator = self._makeOne(renderer='fixtures/minimal.pt')
e6fa66 550         venusian = DummyVenusian()
CM 551         decorator.venusian = venusian
552         def foo(): pass
89968d 553         wrapped = decorator(foo)
a1d395 554         self.assertTrue(wrapped is foo)
b2c4e0 555         config = call_venusian(venusian)
CM 556         settings = config.settings
e6fa66 557         self.assertEqual(len(settings), 1)
3d9dd0 558         renderer = settings[0]['renderer']
b2c4e0 559         self.assertEqual(renderer, 'fixtures/minimal.pt')
CM 560         self.assertEqual(config.pkg, pyramid.tests)
89968d 561
3d9dd0 562     def test_call_with_renderer_dict(self):
b2c4e0 563         import pyramid.tests
3d9dd0 564         decorator = self._makeOne(renderer={'a':1})
e6fa66 565         venusian = DummyVenusian()
CM 566         decorator.venusian = venusian
567         def foo(): pass
89968d 568         wrapped = decorator(foo)
a1d395 569         self.assertTrue(wrapped is foo)
b2c4e0 570         config = call_venusian(venusian)
CM 571         settings = config.settings
e6fa66 572         self.assertEqual(len(settings), 1)
3d9dd0 573         self.assertEqual(settings[0]['renderer'], {'a':1})
b2c4e0 574         self.assertEqual(config.pkg, pyramid.tests)
89968d 575
2ad827 576     def test_call_with_renderer_IRendererInfo(self):
CM 577         import pyramid.tests
b2c4e0 578         from pyramid.interfaces import IRendererInfo
3b7334 579         @implementer(IRendererInfo)
2ad827 580         class DummyRendererHelper(object):
3b7334 581             pass
2ad827 582         renderer_helper = DummyRendererHelper()
CM 583         decorator = self._makeOne(renderer=renderer_helper)
584         venusian = DummyVenusian()
585         decorator.venusian = venusian
586         def foo(): pass
587         wrapped = decorator(foo)
588         self.assertTrue(wrapped is foo)
589         context = DummyVenusianContext()
b2c4e0 590         config = call_venusian(venusian, context)
CM 591         settings = config.settings
2ad827 592         self.assertEqual(len(settings), 1)
CM 593         renderer = settings[0]['renderer']
73c0ae 594         self.assertTrue(renderer is renderer_helper)
b2c4e0 595         self.assertEqual(config.pkg, pyramid.tests)
2ad827 596
a8d71c 597     def test_call_withdepth(self):
ed1419 598         decorator = self._makeOne(_depth=1)
a8d71c 599         venusian = DummyVenusian()
CM 600         decorator.venusian = venusian
601         def foo(): pass
602         decorator(foo)
010971 603         attachments = venusian.attachments
MM 604         depth = attachments[0][3]
605         self.assertEqual(depth, 2)
a8d71c 606
2c5f77 607     def test_call_withoutcategory(self):
T 608         decorator = self._makeOne()
609         venusian = DummyVenusian()
610         decorator.venusian = venusian
611         def foo(): pass
612         decorator(foo)
613         attachments = venusian.attachments
614         category = attachments[0][2]
615         self.assertEqual(category, 'pyramid')
616
617     def test_call_withcategory(self):
618         decorator = self._makeOne(_category='not_pyramid')
619         venusian = DummyVenusian()
620         decorator.venusian = venusian
621         def foo(): pass
622         decorator(foo)
623         attachments = venusian.attachments
624         category = attachments[0][2]
625         self.assertEqual(category, 'not_pyramid')
626
d96ff9 627 class Test_append_slash_notfound_view(BaseTest, unittest.TestCase):
3a61a3 628     def _callFUT(self, context, request):
b60bdb 629         from pyramid.view import append_slash_notfound_view
3a61a3 630         return append_slash_notfound_view(context, request)
CM 631
1c0210 632     def _registerMapper(self, reg, match=True):
b60bdb 633         from pyramid.interfaces import IRoutesMapper
3a61a3 634         class DummyRoute(object):
CM 635             def __init__(self, val):
636                 self.val = val
637             def match(self, path):
638                 return self.val
639         class DummyMapper(object):
640             def __init__(self):
641                 self.routelist = [ DummyRoute(match) ]
06dad2 642             def get_routes(self):
CM 643                 return self.routelist
3a61a3 644         mapper = DummyMapper()
1c0210 645         reg.registerUtility(mapper, IRoutesMapper)
3a61a3 646         return mapper
CM 647
30e64f 648     def test_context_is_not_exception(self):
CM 649         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 650         request.exception = ExceptionResponse()
30e64f 651         context = DummyContext()
CM 652         response = self._callFUT(context, request)
653         self.assertEqual(response.status, '404 Not Found')
d96ff9 654         self.assertEqual(response.app_iter, ['Not Found'])
30e64f 655
3a61a3 656     def test_no_mapper(self):
1c0210 657         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 658         context = ExceptionResponse()
3a61a3 659         response = self._callFUT(context, request)
CM 660         self.assertEqual(response.status, '404 Not Found')
661
662     def test_no_path(self):
1c0210 663         request = self._makeRequest()
d96ff9 664         context = ExceptionResponse()
1c0210 665         self._registerMapper(request.registry, True)
3a61a3 666         response = self._callFUT(context, request)
CM 667         self.assertEqual(response.status, '404 Not Found')
668
669     def test_mapper_path_already_slash_ending(self):
1c0210 670         request = self._makeRequest(PATH_INFO='/abc/')
d96ff9 671         context = ExceptionResponse()
1c0210 672         self._registerMapper(request.registry, True)
3a61a3 673         response = self._callFUT(context, request)
CM 674         self.assertEqual(response.status, '404 Not Found')
675
d92958 676     def test_no_route_matches(self):
CM 677         request = self._makeRequest(PATH_INFO='/abc')
678         context = ExceptionResponse()
679         mapper = self._registerMapper(request.registry, True)
680         mapper.routelist[0].val = None
681         response = self._callFUT(context, request)
682         self.assertEqual(response.status, '404 Not Found')
683
3a61a3 684     def test_matches(self):
1c0210 685         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 686         context = ExceptionResponse()
1c0210 687         self._registerMapper(request.registry, True)
3a61a3 688         response = self._callFUT(context, request)
CM 689         self.assertEqual(response.status, '302 Found')
690         self.assertEqual(response.location, '/abc/')
691
b596e1 692     def test_matches_with_script_name(self):
CM 693         request = self._makeRequest(PATH_INFO='/abc', SCRIPT_NAME='/foo')
694         context = ExceptionResponse()
695         self._registerMapper(request.registry, True)
696         response = self._callFUT(context, request)
697         self.assertEqual(response.status, '302 Found')
698         self.assertEqual(response.location, '/foo/abc/')
699
6ab71c 700     def test_with_query_string(self):
CM 701         request = self._makeRequest(PATH_INFO='/abc', QUERY_STRING='a=1&b=2')
702         context = ExceptionResponse()
703         self._registerMapper(request.registry, True)
704         response = self._callFUT(context, request)
705         self.assertEqual(response.status, '302 Found')
706         self.assertEqual(response.location, '/abc/?a=1&b=2')
707
d96ff9 708 class TestAppendSlashNotFoundViewFactory(BaseTest, unittest.TestCase):
CM 709     def _makeOne(self, notfound_view):
b60bdb 710         from pyramid.view import AppendSlashNotFoundViewFactory
d96ff9 711         return AppendSlashNotFoundViewFactory(notfound_view)
CM 712     
713     def test_custom_notfound_view(self):
714         request = self._makeRequest(PATH_INFO='/abc')
715         context = ExceptionResponse()
716         def custom_notfound(context, request):
717             return 'OK'
718         view = self._makeOne(custom_notfound)
719         response = view(context, request)
720         self.assertEqual(response, 'OK')
721
722 class Test_default_exceptionresponse_view(unittest.TestCase):
723     def _callFUT(self, context, request):
b60bdb 724         from pyramid.view import default_exceptionresponse_view
d96ff9 725         return default_exceptionresponse_view(context, request)
CM 726
727     def test_is_exception(self):
728         context = Exception()
729         result = self._callFUT(context, None)
a1d395 730         self.assertTrue(result is context)
d96ff9 731
b04bd5 732     def test_is_not_exception_context_is_false_still_chose(self):
d92958 733         request = DummyRequest()
CM 734         request.exception = 0
735         result = self._callFUT(None, request)
a1d395 736         self.assertTrue(result is None)
d92958 737
d96ff9 738     def test_is_not_exception_no_request_exception(self):
CM 739         context = object()
740         request = DummyRequest()
d92958 741         request.exception = None
d96ff9 742         result = self._callFUT(context, request)
a1d395 743         self.assertTrue(result is context)
d96ff9 744
CM 745     def test_is_not_exception_request_exception(self):
746         context = object()
747         request = DummyRequest()
748         request.exception = 'abc'
749         result = self._callFUT(context, request)
750         self.assertEqual(result, 'abc')
751
914abe 752 class Test_view_defaults(unittest.TestCase):
CM 753     def test_it(self):
754         from pyramid.view import view_defaults
755         @view_defaults(route_name='abc', renderer='def')
756         class Foo(object): pass
757         self.assertEqual(Foo.__view_defaults__['route_name'],'abc')
758         self.assertEqual(Foo.__view_defaults__['renderer'],'def')
759
4375cf 760     def test_it_inheritance_not_overridden(self):
914abe 761         from pyramid.view import view_defaults
CM 762         @view_defaults(route_name='abc', renderer='def')
763         class Foo(object): pass
764         class Bar(Foo): pass
765         self.assertEqual(Bar.__view_defaults__['route_name'],'abc')
766         self.assertEqual(Bar.__view_defaults__['renderer'],'def')
767
4375cf 768     def test_it_inheritance_overriden(self):
CM 769         from pyramid.view import view_defaults
770         @view_defaults(route_name='abc', renderer='def')
771         class Foo(object): pass
772         @view_defaults(route_name='ghi')
773         class Bar(Foo): pass
774         self.assertEqual(Bar.__view_defaults__['route_name'],'ghi')
4c29ef 775         self.assertFalse('renderer' in Bar.__view_defaults__)
4375cf 776
CM 777     def test_it_inheritance_overriden_empty(self):
778         from pyramid.view import view_defaults
779         @view_defaults(route_name='abc', renderer='def')
780         class Foo(object): pass
781         @view_defaults()
782         class Bar(Foo): pass
4c29ef 783         self.assertEqual(Bar.__view_defaults__, {})
4375cf 784
d52257 785 class TestViewMethodsMixin(unittest.TestCase):
MM 786     def setUp(self):
787         self.config = testing.setUp()
788
789     def tearDown(self):
790         testing.tearDown()
791
792     def _makeOne(self, environ=None):
793         from pyramid.decorator import reify
794         from pyramid.view import ViewMethodsMixin
795         if environ is None:
796             environ = {}
797         class Request(ViewMethodsMixin):
798             def __init__(self, environ):
799                 self.environ = environ
800
801             @reify
802             def response(self):
803                 return DummyResponse()
804         request = Request(environ)
805         request.registry = self.config.registry
806         return request
807
808     def test_it(self):
809         def exc_view(exc, request):
810             self.assertTrue(exc is dummy_exc)
811             self.assertTrue(request.exception is dummy_exc)
812             return DummyResponse(b'foo')
813         self.config.add_view(exc_view, context=RuntimeError)
814         request = self._makeOne()
815         dummy_exc = RuntimeError()
816         try:
817             raise dummy_exc
818         except RuntimeError:
819             response = request.invoke_exception_view()
820             self.assertEqual(response.app_iter, [b'foo'])
821         else: # pragma: no cover
822             self.fail()
823
824     def test_it_hides_attrs(self):
825         def exc_view(exc, request):
826             self.assertTrue(exc is not orig_exc)
827             self.assertTrue(request.exception is not orig_exc)
828             self.assertTrue(request.exc_info is not orig_exc_info)
829             self.assertTrue(request.response is not orig_response)
830             request.response.app_iter = [b'bar']
831             return request.response
832         self.config.add_view(exc_view, context=RuntimeError)
833         request = self._makeOne()
834         orig_exc = request.exception = DummyContext()
835         orig_exc_info = request.exc_info = DummyContext()
836         orig_response = request.response = DummyResponse(b'foo')
837         try:
838             raise RuntimeError
3b886e 839         except RuntimeError as ex:
d52257 840             response = request.invoke_exception_view()
MM 841             self.assertEqual(response.app_iter, [b'bar'])
3b886e 842             self.assertTrue(request.exception is ex)
MM 843             self.assertTrue(request.exc_info[1] is ex)
d52257 844             self.assertTrue(request.response is orig_response)
MM 845         else: # pragma: no cover
846             self.fail()
847
848     def test_it_supports_alternate_requests(self):
849         def exc_view(exc, request):
850             self.assertTrue(request is other_req)
dda9fa 851             from pyramid.threadlocal import get_current_request
BJR 852             self.assertTrue(get_current_request() is other_req)
d52257 853             return DummyResponse(b'foo')
MM 854         self.config.add_view(exc_view, context=RuntimeError)
855         request = self._makeOne()
856         other_req = self._makeOne()
857         try:
858             raise RuntimeError
859         except RuntimeError:
860             response = request.invoke_exception_view(request=other_req)
861             self.assertEqual(response.app_iter, [b'foo'])
862         else: # pragma: no cover
863             self.fail()
864
865     def test_it_supports_threadlocal_registry(self):
866         def exc_view(exc, request):
867             return DummyResponse(b'foo')
868         self.config.add_view(exc_view, context=RuntimeError)
869         request = self._makeOne()
870         del request.registry
871         try:
872             raise RuntimeError
873         except RuntimeError:
874             response = request.invoke_exception_view()
875             self.assertEqual(response.app_iter, [b'foo'])
876         else: # pragma: no cover
877             self.fail()
878
dda9fa 879     def test_it_raises_if_no_registry(self):
BJR 880         request = self._makeOne()
881         del request.registry
882         from pyramid.threadlocal import manager
883         manager.push({'registry': None, 'request': request})
884         try:
885             raise RuntimeError
886         except RuntimeError:
887             try:
888                 request.invoke_exception_view()
889             except RuntimeError as e:
890                 self.assertEqual(e.args[0], "Unable to retrieve registry")
891         else: # pragma: no cover
892             self.fail()
893         finally:
894             manager.pop()
895
d52257 896     def test_it_supports_alternate_exc_info(self):
MM 897         def exc_view(exc, request):
898             self.assertTrue(request.exc_info is exc_info)
899             return DummyResponse(b'foo')
900         self.config.add_view(exc_view, context=RuntimeError)
901         request = self._makeOne()
902         try:
903             raise RuntimeError
904         except RuntimeError:
905             exc_info = sys.exc_info()
906         response = request.invoke_exception_view(exc_info=exc_info)
907         self.assertEqual(response.app_iter, [b'foo'])
908
909     def test_it_rejects_secured_view(self):
910         from pyramid.exceptions import Forbidden
911         def exc_view(exc, request): pass
912         self.config.testing_securitypolicy(permissive=False)
913         self.config.add_view(exc_view, context=RuntimeError, permission='view')
914         request = self._makeOne()
915         try:
916             raise RuntimeError
917         except RuntimeError:
918             self.assertRaises(Forbidden, request.invoke_exception_view)
919         else: # pragma: no cover
920             self.fail()
921
922     def test_it_allows_secured_view(self):
923         def exc_view(exc, request):
924             return DummyResponse(b'foo')
925         self.config.testing_securitypolicy(permissive=False)
926         self.config.add_view(exc_view, context=RuntimeError, permission='view')
927         request = self._makeOne()
928         try:
929             raise RuntimeError
930         except RuntimeError:
931             response = request.invoke_exception_view(secure=False)
932             self.assertEqual(response.app_iter, [b'foo'])
933         else: # pragma: no cover
934             self.fail()
935
e045cf 936     def test_it_raises_if_not_found(self):
MM 937         from pyramid.httpexceptions import HTTPNotFound
938         request = self._makeOne()
939         dummy_exc = RuntimeError()
940         try:
941             raise dummy_exc
942         except RuntimeError:
943             self.assertRaises(HTTPNotFound, request.invoke_exception_view)
944         else: # pragma: no cover
945             self.fail()
946
6f2f04 947     def test_it_reraises_if_not_found(self):
MM 948         request = self._makeOne()
949         dummy_exc = RuntimeError()
950         try:
951             raise dummy_exc
952         except RuntimeError:
953             self.assertRaises(
954                 RuntimeError,
955                 lambda: request.invoke_exception_view(reraise=True))
956         else: # pragma: no cover
957             self.fail()
958
e045cf 959     def test_it_raises_predicate_mismatch(self):
MM 960         from pyramid.exceptions import PredicateMismatch
961         def exc_view(exc, request): pass
962         self.config.add_view(exc_view, context=Exception, request_method='POST')
963         request = self._makeOne()
964         request.method = 'GET'
965         dummy_exc = RuntimeError()
966         try:
967             raise dummy_exc
968         except RuntimeError:
969             self.assertRaises(PredicateMismatch, request.invoke_exception_view)
970         else: # pragma: no cover
971             self.fail()
972
6f2f04 973     def test_it_reraises_after_predicate_mismatch(self):
MM 974         def exc_view(exc, request): pass
975         self.config.add_view(exc_view, context=Exception, request_method='POST')
976         request = self._makeOne()
977         request.method = 'GET'
978         dummy_exc = RuntimeError()
979         try:
980             raise dummy_exc
981         except RuntimeError:
982             self.assertRaises(
983                 RuntimeError,
984                 lambda: request.invoke_exception_view(reraise=True))
985         else: # pragma: no cover
986             self.fail()
987
d96ff9 988 class ExceptionResponse(Exception):
CM 989     status = '404 Not Found'
990     app_iter = ['Not Found']
991     headerlist = []
e06153 992
7e2c6c 993 class DummyContext:
CM 994     pass
17ce57 995
7e2c6c 996 def make_view(response):
CM 997     def view(context, request):
998         return response
999     return view
1000
d96ff9 1001 class DummyRequest:
d3e48e 1002     exception = None
849196 1003     request_iface = IRequest
d96ff9 1004
56d0fe 1005     def __init__(self, environ=None):
CM 1006         if environ is None:
1007             environ = {}
1008         self.environ = environ
1009         
d868ff 1010 from pyramid.interfaces import IResponse
CM 1011
3b7334 1012 @implementer(IResponse)
d868ff 1013 class DummyResponse(object):
7e2c6c 1014     headerlist = ()
d868ff 1015     app_iter = ()
CM 1016     status = '200 OK'
1017     environ = None
d66bfb 1018     def __init__(self, body=None):
CM 1019         if body is None:
1020             self.app_iter = ()
1021         else:
1022             self.app_iter = [body]
7df825 1023
1c0210 1024 from zope.interface import Interface
CM 1025 class IContext(Interface):
1026     pass
e6fa66 1027
CM 1028 class DummyVenusianInfo(object):
1029     scope = 'notaclass'
b60bdb 1030     module = sys.modules['pyramid.tests']
14b78b 1031     codeinfo = 'codeinfo'
e6fa66 1032
CM 1033 class DummyVenusian(object):
1034     def __init__(self, info=None):
1035         if info is None:
1036             info = DummyVenusianInfo()
1037         self.info = info
1038         self.attachments = []
1039
a8d71c 1040     def attach(self, wrapped, callback, category=None, depth=1):
010971 1041         self.attachments.append((wrapped, callback, category, depth))
e6fa66 1042         return self.info
CM 1043
95c9f6 1044 class DummyRegistry(object):
CM 1045     pass
1046
e6fa66 1047 class DummyConfig(object):
CM 1048     def __init__(self):
1049         self.settings = []
95c9f6 1050         self.registry = DummyRegistry()
e6fa66 1051
CM 1052     def add_view(self, **kw):
1053         self.settings.append(kw)
1054
93c94b 1055     add_notfound_view = add_forbidden_view = add_exception_view = add_view
0db4a1 1056
b2c4e0 1057     def with_package(self, pkg):
CM 1058         self.pkg = pkg
1059         return self
1060
e6fa66 1061 class DummyVenusianContext(object):
CM 1062     def __init__(self):
1063         self.config = DummyConfig()
1064         
2ad827 1065 def call_venusian(venusian, context=None):
CM 1066     if context is None:
1067         context = DummyVenusianContext()
010971 1068     for wrapped, callback, category, depth in venusian.attachments:
e6fa66 1069         callback(context, None, None)
b2c4e0 1070     return context.config
e6fa66 1071