Michael Merickel
2018-10-26 4149922e64aecf2a213f8efb120cd2d61fed3eb7
commit | author | age
5bf23f 1 import unittest
52fde9 2
d6ff99 3 from pyramid.compat import text_
52fde9 4
0c29cf 5
9c8ec5 6 class TestPredicateList(unittest.TestCase):
CM 7     def _makeOne(self):
d579f2 8         from pyramid.config.predicates import PredicateList
c7974f 9         from pyramid import predicates
0c29cf 10
9c8ec5 11         inst = PredicateList()
CM 12         for name, factory in (
13             ('xhr', predicates.XHRPredicate),
14             ('request_method', predicates.RequestMethodPredicate),
15             ('path_info', predicates.PathInfoPredicate),
16             ('request_param', predicates.RequestParamPredicate),
17             ('header', predicates.HeaderPredicate),
18             ('accept', predicates.AcceptPredicate),
19             ('containment', predicates.ContainmentPredicate),
20             ('request_type', predicates.RequestTypePredicate),
21             ('match_param', predicates.MatchParamPredicate),
22             ('custom', predicates.CustomPredicate),
23             ('traverse', predicates.TraversePredicate),
0c29cf 24         ):
9c8ec5 25             inst.add(name, factory)
CM 26         return inst
27
5bf23f 28     def _callFUT(self, **kw):
9c8ec5 29         inst = self._makeOne()
CM 30         config = DummyConfigurator()
31         return inst.make(config, **kw)
5bf23f 32
CM 33     def test_ordering_xhr_and_request_method_trump_only_containment(self):
34         order1, _, _ = self._callFUT(xhr=True, request_method='GET')
35         order2, _, _ = self._callFUT(containment=True)
36         self.assertTrue(order1 < order2)
37
38     def test_ordering_number_of_predicates(self):
d579f2 39         from pyramid.config.predicates import predvalseq
0c29cf 40
5bf23f 41         order1, _, _ = self._callFUT(
CM 42             xhr='xhr',
43             request_method='request_method',
44             path_info='path_info',
45             request_param='param',
718a44 46             match_param='foo=bar',
5bf23f 47             header='header',
CM 48             accept='accept',
49             containment='containment',
50             request_type='request_type',
9c8ec5 51             custom=predvalseq([DummyCustomPredicate()]),
0c29cf 52         )
5bf23f 53         order2, _, _ = self._callFUT(
CM 54             xhr='xhr',
55             request_method='request_method',
56             path_info='path_info',
57             request_param='param',
718a44 58             match_param='foo=bar',
5bf23f 59             header='header',
CM 60             accept='accept',
61             containment='containment',
62             request_type='request_type',
9c8ec5 63             custom=predvalseq([DummyCustomPredicate()]),
0c29cf 64         )
5bf23f 65         order3, _, _ = self._callFUT(
CM 66             xhr='xhr',
67             request_method='request_method',
68             path_info='path_info',
69             request_param='param',
718a44 70             match_param='foo=bar',
5bf23f 71             header='header',
CM 72             accept='accept',
73             containment='containment',
74             request_type='request_type',
0c29cf 75         )
5bf23f 76         order4, _, _ = self._callFUT(
CM 77             xhr='xhr',
78             request_method='request_method',
79             path_info='path_info',
80             request_param='param',
718a44 81             match_param='foo=bar',
5bf23f 82             header='header',
CM 83             accept='accept',
84             containment='containment',
0c29cf 85         )
5bf23f 86         order5, _, _ = self._callFUT(
CM 87             xhr='xhr',
88             request_method='request_method',
89             path_info='path_info',
90             request_param='param',
718a44 91             match_param='foo=bar',
5bf23f 92             header='header',
CM 93             accept='accept',
0c29cf 94         )
5bf23f 95         order6, _, _ = self._callFUT(
CM 96             xhr='xhr',
97             request_method='request_method',
98             path_info='path_info',
99             request_param='param',
718a44 100             match_param='foo=bar',
5bf23f 101             header='header',
0c29cf 102         )
5bf23f 103         order7, _, _ = self._callFUT(
CM 104             xhr='xhr',
105             request_method='request_method',
106             path_info='path_info',
107             request_param='param',
718a44 108             match_param='foo=bar',
0c29cf 109         )
5bf23f 110         order8, _, _ = self._callFUT(
CM 111             xhr='xhr',
112             request_method='request_method',
113             path_info='path_info',
718a44 114             request_param='param',
0c29cf 115         )
5bf23f 116         order9, _, _ = self._callFUT(
0c29cf 117             xhr='xhr', request_method='request_method', path_info='path_info'
MM 118         )
5bf23f 119         order10, _, _ = self._callFUT(
0c29cf 120             xhr='xhr', request_method='request_method'
MM 121         )
122         order11, _, _ = self._callFUT(xhr='xhr')
123         order12, _, _ = self._callFUT()
5bf23f 124         self.assertEqual(order1, order2)
CM 125         self.assertTrue(order3 > order2)
126         self.assertTrue(order4 > order3)
127         self.assertTrue(order5 > order4)
128         self.assertTrue(order6 > order5)
129         self.assertTrue(order7 > order6)
130         self.assertTrue(order8 > order7)
131         self.assertTrue(order9 > order8)
132         self.assertTrue(order10 > order9)
133         self.assertTrue(order11 > order10)
718a44 134         self.assertTrue(order12 > order10)
5bf23f 135
CM 136     def test_ordering_importance_of_predicates(self):
d579f2 137         from pyramid.config.predicates import predvalseq
0c29cf 138
MM 139         order1, _, _ = self._callFUT(xhr='xhr')
140         order2, _, _ = self._callFUT(request_method='request_method')
141         order3, _, _ = self._callFUT(path_info='path_info')
142         order4, _, _ = self._callFUT(request_param='param')
143         order5, _, _ = self._callFUT(header='header')
144         order6, _, _ = self._callFUT(accept='accept')
145         order7, _, _ = self._callFUT(containment='containment')
146         order8, _, _ = self._callFUT(request_type='request_type')
147         order9, _, _ = self._callFUT(match_param='foo=bar')
718a44 148         order10, _, _ = self._callFUT(
0c29cf 149             custom=predvalseq([DummyCustomPredicate()])
MM 150         )
5bf23f 151         self.assertTrue(order1 > order2)
CM 152         self.assertTrue(order2 > order3)
153         self.assertTrue(order3 > order4)
154         self.assertTrue(order4 > order5)
155         self.assertTrue(order5 > order6)
156         self.assertTrue(order6 > order7)
157         self.assertTrue(order7 > order8)
158         self.assertTrue(order8 > order9)
718a44 159         self.assertTrue(order9 > order10)
5bf23f 160
CM 161     def test_ordering_importance_and_number(self):
d579f2 162         from pyramid.config.predicates import predvalseq
0c29cf 163
5bf23f 164         order1, _, _ = self._callFUT(
0c29cf 165             xhr='xhr', request_method='request_method'
MM 166         )
5bf23f 167         order2, _, _ = self._callFUT(
0c29cf 168             custom=predvalseq([DummyCustomPredicate()])
MM 169         )
5bf23f 170         self.assertTrue(order1 < order2)
CM 171
172         order1, _, _ = self._callFUT(
0c29cf 173             xhr='xhr', request_method='request_method'
MM 174         )
5bf23f 175         order2, _, _ = self._callFUT(
CM 176             request_method='request_method',
9c8ec5 177             custom=predvalseq([DummyCustomPredicate()]),
0c29cf 178         )
5bf23f 179         self.assertTrue(order1 > order2)
CM 180
181         order1, _, _ = self._callFUT(
0c29cf 182             xhr='xhr', request_method='request_method', path_info='path_info'
MM 183         )
5bf23f 184         order2, _, _ = self._callFUT(
CM 185             request_method='request_method',
9c8ec5 186             custom=predvalseq([DummyCustomPredicate()]),
0c29cf 187         )
5bf23f 188         self.assertTrue(order1 < order2)
CM 189
190         order1, _, _ = self._callFUT(
0c29cf 191             xhr='xhr', request_method='request_method', path_info='path_info'
MM 192         )
5bf23f 193         order2, _, _ = self._callFUT(
CM 194             xhr='xhr',
195             request_method='request_method',
9c8ec5 196             custom=predvalseq([DummyCustomPredicate()]),
0c29cf 197         )
5bf23f 198         self.assertTrue(order1 > order2)
CM 199
200     def test_different_custom_predicates_with_same_hash(self):
d579f2 201         from pyramid.config.predicates import predvalseq
0c29cf 202
5bf23f 203         class PredicateWithHash(object):
CM 204             def __hash__(self):
205                 return 1
0c29cf 206
5bf23f 207         a = PredicateWithHash()
CM 208         b = PredicateWithHash()
9c8ec5 209         _, _, a_phash = self._callFUT(custom=predvalseq([a]))
CM 210         _, _, b_phash = self._callFUT(custom=predvalseq([b]))
5bf23f 211         self.assertEqual(a_phash, b_phash)
CM 212
213     def test_traverse_has_remainder_already(self):
214         order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
215         self.assertEqual(len(predicates), 1)
216         pred = predicates[0]
0c29cf 217         info = {'traverse': 'abc'}
5bf23f 218         request = DummyRequest()
CM 219         result = pred(info, request)
220         self.assertEqual(result, True)
0c29cf 221         self.assertEqual(info, {'traverse': 'abc'})
5bf23f 222
CM 223     def test_traverse_matches(self):
224         order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
225         self.assertEqual(len(predicates), 1)
226         pred = predicates[0]
0c29cf 227         info = {'match': {'a': 'a', 'b': 'b'}}
5bf23f 228         request = DummyRequest()
CM 229         result = pred(info, request)
230         self.assertEqual(result, True)
0c29cf 231         self.assertEqual(
MM 232             info, {'match': {'a': 'a', 'b': 'b', 'traverse': ('1', 'a', 'b')}}
233         )
5bf23f 234
586401 235     def test_traverse_matches_with_highorder_chars(self):
CM 236         order, predicates, phash = self._callFUT(
0c29cf 237             traverse=text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8')
MM 238         )
586401 239         self.assertEqual(len(predicates), 1)
CM 240         pred = predicates[0]
0c29cf 241         info = {'match': {'x': text_(b'Qu\xc3\xa9bec', 'utf-8')}}
586401 242         request = DummyRequest()
CM 243         result = pred(info, request)
244         self.assertEqual(result, True)
245         self.assertEqual(
246             info['match']['traverse'],
0c29cf 247             (
MM 248                 text_(b'La Pe\xc3\xb1a', 'utf-8'),
249                 text_(b'Qu\xc3\xa9bec', 'utf-8'),
250             ),
251         )
586401 252
c81dbd 253     def test_custom_predicates_can_affect_traversal(self):
d579f2 254         from pyramid.config.predicates import predvalseq
0c29cf 255
c81dbd 256         def custom(info, request):
MM 257             m = info['match']
258             m['dummy'] = 'foo'
259             return True
0c29cf 260
9c8ec5 261         _, predicates, _ = self._callFUT(
0c29cf 262             custom=predvalseq([custom]), traverse='/1/:dummy/:a'
MM 263         )
c81dbd 264         self.assertEqual(len(predicates), 2)
0c29cf 265         info = {'match': {'a': 'a'}}
c81dbd 266         request = DummyRequest()
MM 267         self.assertTrue(all([p(info, request) for p in predicates]))
0c29cf 268         self.assertEqual(
MM 269             info,
270             {
271                 'match': {
272                     'a': 'a',
273                     'dummy': 'foo',
274                     'traverse': ('1', 'foo', 'a'),
275                 }
276             },
277         )
c81dbd 278
5bf23f 279     def test_predicate_text_is_correct(self):
d579f2 280         from pyramid.config.predicates import predvalseq
0c29cf 281
5bf23f 282         _, predicates, _ = self._callFUT(
CM 283             xhr='xhr',
284             request_method='request_method',
285             path_info='path_info',
286             request_param='param',
287             header='header',
288             accept='accept',
289             containment='containment',
290             request_type='request_type',
9c8ec5 291             custom=predvalseq(
CM 292                 [
293                     DummyCustomPredicate(),
5bf23f 294                     DummyCustomPredicate.classmethod_predicate,
9c8ec5 295                     DummyCustomPredicate.classmethod_predicate_no_text,
CM 296                 ]
297             ),
0c29cf 298             match_param='foo=bar',
MM 299         )
9c8ec5 300         self.assertEqual(predicates[0].text(), 'xhr = True')
0c29cf 301         self.assertEqual(
MM 302             predicates[1].text(), "request_method = request_method"
303         )
9c8ec5 304         self.assertEqual(predicates[2].text(), 'path_info = path_info')
CM 305         self.assertEqual(predicates[3].text(), 'request_param param')
306         self.assertEqual(predicates[4].text(), 'header header')
307         self.assertEqual(predicates[5].text(), 'accept = accept')
308         self.assertEqual(predicates[6].text(), 'containment = containment')
309         self.assertEqual(predicates[7].text(), 'request_type = request_type')
310         self.assertEqual(predicates[8].text(), "match_param foo=bar")
311         self.assertEqual(predicates[9].text(), 'custom predicate')
312         self.assertEqual(predicates[10].text(), 'classmethod predicate')
313         self.assertTrue(predicates[11].text().startswith('custom predicate'))
718a44 314
MM 315     def test_match_param_from_string(self):
316         _, predicates, _ = self._callFUT(match_param='foo=bar')
317         request = DummyRequest()
0c29cf 318         request.matchdict = {'foo': 'bar', 'baz': 'bum'}
718a44 319         self.assertTrue(predicates[0](Dummy(), request))
MM 320
321     def test_match_param_from_string_fails(self):
322         _, predicates, _ = self._callFUT(match_param='foo=bar')
323         request = DummyRequest()
0c29cf 324         request.matchdict = {'foo': 'bum', 'baz': 'bum'}
718a44 325         self.assertFalse(predicates[0](Dummy(), request))
MM 326
327     def test_match_param_from_dict(self):
0c29cf 328         _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum'))
718a44 329         request = DummyRequest()
0c29cf 330         request.matchdict = {'foo': 'bar', 'baz': 'bum'}
718a44 331         self.assertTrue(predicates[0](Dummy(), request))
MM 332
333     def test_match_param_from_dict_fails(self):
0c29cf 334         _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum'))
718a44 335         request = DummyRequest()
0c29cf 336         request.matchdict = {'foo': 'bar', 'baz': 'foo'}
718a44 337         self.assertFalse(predicates[0](Dummy(), request))
5bf23f 338
49f082 339     def test_request_method_sequence(self):
CM 340         _, predicates, _ = self._callFUT(request_method=('GET', 'HEAD'))
341         request = DummyRequest()
342         request.method = 'HEAD'
343         self.assertTrue(predicates[0](Dummy(), request))
344         request.method = 'GET'
345         self.assertTrue(predicates[0](Dummy(), request))
346         request.method = 'POST'
347         self.assertFalse(predicates[0](Dummy(), request))
348
349     def test_request_method_ordering_hashes_same(self):
0c29cf 350         hash1, _, __ = self._callFUT(request_method=('GET', 'HEAD'))
MM 351         hash2, _, __ = self._callFUT(request_method=('HEAD', 'GET'))
49f082 352         self.assertEqual(hash1, hash2)
0c29cf 353         hash1, _, __ = self._callFUT(request_method=('GET',))
MM 354         hash2, _, __ = self._callFUT(request_method='GET')
49f082 355         self.assertEqual(hash1, hash2)
CM 356
adf323 357     def test_unknown_predicate(self):
CM 358         from pyramid.exceptions import ConfigurationError
0c29cf 359
adf323 360         self.assertRaises(ConfigurationError, self._callFUT, unknown=1)
32333e 361
aafaf7 362     def test_predicate_close_matches(self):
FL 363         from pyramid.exceptions import ConfigurationError
0c29cf 364
MM 365         with self.assertRaises(ConfigurationError) as context:
aafaf7 366             self._callFUT(method='GET')
FL 367         expected_msg = (
368             "Unknown predicate values: {'method': 'GET'} "
369             "(did you mean request_method)"
370         )
371         self.assertEqual(context.exception.args[0], expected_msg)
372
32333e 373     def test_notted(self):
CM 374         from pyramid.config import not_
375         from pyramid.testing import DummyRequest
0c29cf 376
32333e 377         request = DummyRequest()
CM 378         _, predicates, _ = self._callFUT(
0c29cf 379             xhr='xhr', request_method=not_('POST'), header=not_('header')
MM 380         )
32333e 381         self.assertEqual(predicates[0].text(), 'xhr = True')
0c29cf 382         self.assertEqual(predicates[1].text(), "!request_method = POST")
32333e 383         self.assertEqual(predicates[2].text(), '!header header')
CM 384         self.assertEqual(predicates[1](None, request), True)
385         self.assertEqual(predicates[2](None, request), True)
b098c2 386
0c29cf 387
f2294f 388 class Test_sort_accept_offers(unittest.TestCase):
MM 389     def _callFUT(self, offers, order=None):
d579f2 390         from pyramid.config.predicates import sort_accept_offers
0c29cf 391
f2294f 392         return sort_accept_offers(offers, order)
MM 393
394     def test_default_specificities(self):
4a9f4f 395         result = self._callFUT(['text/html', 'text/html;charset=utf8'])
0c29cf 396         self.assertEqual(result, ['text/html;charset=utf8', 'text/html'])
f2294f 397
MM 398     def test_specific_type_order(self):
399         result = self._callFUT(
0c29cf 400             [
MM 401                 'text/html',
402                 'application/json',
403                 'text/html;charset=utf8',
404                 'text/plain',
405             ],
f2294f 406             ['application/json', 'text/html'],
MM 407         )
0c29cf 408         self.assertEqual(
MM 409             result,
410             [
411                 'application/json',
412                 'text/html;charset=utf8',
413                 'text/html',
414                 'text/plain',
415             ],
416         )
f2294f 417
MM 418     def test_params_order(self):
419         result = self._callFUT(
0c29cf 420             [
MM 421                 'text/html;charset=utf8',
422                 'text/html;charset=latin1',
423                 'text/html;foo=bar',
424             ],
f2294f 425             ['text/html;charset=latin1', 'text/html;charset=utf8'],
MM 426         )
0c29cf 427         self.assertEqual(
MM 428             result,
429             [
430                 'text/html;charset=latin1',
431                 'text/html;charset=utf8',
432                 'text/html;foo=bar',
433             ],
434         )
f2294f 435
MM 436     def test_params_inherit_type_prefs(self):
437         result = self._callFUT(
438             ['text/html;charset=utf8', 'text/plain;charset=latin1'],
439             ['text/plain', 'text/html'],
440         )
0c29cf 441         self.assertEqual(
MM 442             result, ['text/plain;charset=latin1', 'text/html;charset=utf8']
443         )
444
f2294f 445
5bf23f 446 class DummyCustomPredicate(object):
CM 447     def __init__(self):
448         self.__text__ = 'custom predicate'
449
10ddb6 450     def classmethod_predicate(*args):  # pragma: no cover
0c29cf 451         pass
MM 452
5bf23f 453     classmethod_predicate.__text__ = 'classmethod predicate'
CM 454     classmethod_predicate = classmethod(classmethod_predicate)
455
456     @classmethod
0c29cf 457     def classmethod_predicate_no_text(*args):
MM 458         pass  # pragma: no cover
459
5bf23f 460
52fde9 461 class Dummy(object):
MM 462     def __init__(self, **kw):
463         self.__dict__.update(**kw)
718a44 464
0c29cf 465
5bf23f 466 class DummyRequest:
CM 467     subpath = ()
468     matchdict = None
0c29cf 469
5bf23f 470     def __init__(self, environ=None):
CM 471         if environ is None:
472             environ = {}
473         self.environ = environ
474         self.params = {}
475         self.cookies = {}
476
0c29cf 477
9c8ec5 478 class DummyConfigurator(object):
CM 479     def maybe_dotted(self, thing):
480         return thing