comparison tests/test_routing.py @ 792:58ebf50235a5

routing: Simplify how routes are defined. * No more declaring the type of route parameters -- the sources and generators already know what type each parameter is supposed to be. * Same for variadic parameters -- we know already. * Update cache version to force a clear reload of the config. * Update tests. TODO: simplify code in the `Route` class to use source or generator transparently.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 07 Sep 2016 08:58:41 -0700
parents f6f9a284a5f3
children 72f17534d58e
comparison
equal deleted inserted replaced
791:504d6817352d 792:58ebf50235a5
1 import urllib.parse 1 import urllib.parse
2 import mock
2 import pytest 3 import pytest
3 from piecrust.routing import Route 4 from piecrust.routing import Route, RouteParameter
5 from piecrust.sources.base import PageSource
4 from .mockutil import get_mock_app 6 from .mockutil import get_mock_app
5 7
6 8
7 @pytest.mark.parametrize( 9 def _getMockSource(name, params):
8 'config, metadata, expected', 10 route_params = []
11 for p in params:
12 if isinstance(p, tuple):
13 if p[1] == 'path':
14 t = RouteParameter.TYPE_PATH
15 elif p[1] == 'int2':
16 t = RouteParameter.TYPE_INT2
17 elif p[2] == 'int4':
18 t = RouteParameter.TYPE_INT4
19 route_params.append(RouteParameter(p[0], t))
20 else:
21 route_params.append(RouteParameter(p, RouteParameter.TYPE_STRING))
22
23 src = mock.MagicMock(spec=PageSource)
24 src.name = name
25 src.getSupportedRouteParameters = lambda: route_params
26 return src
27
28
29 @pytest.mark.parametrize(
30 'config, metadata, params, expected',
9 [ 31 [
10 ({'url': '/%foo%'}, 32 ({'url': '/%foo%'},
11 {'foo': 'bar'}, True), 33 {'foo': 'bar'}, ['foo'], True),
12 ({'url': '/%foo%'}, 34 ({'url': '/%foo%'},
13 {'zoo': 'zar', 'foo': 'bar'}, True), 35 {'zoo': 'zar', 'foo': 'bar'}, ['foo'], True),
14 ({'url': '/%foo%'}, 36 ({'url': '/%foo%'},
15 {'zoo': 'zar'}, False), 37 {'zoo': 'zar'}, ['foo'], False),
16 ({'url': '/%foo%/%zoo%'}, 38 ({'url': '/%foo%/%zoo%'},
17 {'zoo': 'zar'}, False) 39 {'zoo': 'zar'}, ['foo', 'zoo'], False)
18 ]) 40 ])
19 def test_matches_metadata(config, metadata, expected): 41 def test_matches_metadata(config, metadata, params, expected):
20 app = get_mock_app() 42 app = get_mock_app()
21 app.config.set('site/root', '/') 43 app.config.set('site/root', '/')
44 app.sources = [_getMockSource('blah', params)]
45
22 config.setdefault('source', 'blah') 46 config.setdefault('source', 'blah')
23 route = Route(app, config) 47 route = Route(app, config)
24 m = route.matchesMetadata(metadata) 48 m = route.matchesMetadata(metadata)
25 assert m == expected 49 assert m == expected
26 50
27 51
28 @pytest.mark.parametrize( 52 @pytest.mark.parametrize(
29 'site_root, route_pattern, expected_func_parameters', 53 'site_root, route_pattern, params, expected_func_parameters',
30 [ 54 [
31 ('/', '/%foo%', ['foo']), 55 ('/', '/%foo%', ['foo'], ['foo']),
32 ('/', '/%path:foo%', ['foo']), 56 ('/', '/%foo%', [('foo', 'path')], ['foo']),
33 ('/', '/%foo%/%bar%', ['foo', 'bar']), 57 ('/', '/%foo%/%bar%', ['foo', 'bar'], ['foo', 'bar']),
34 ('/', '/%foo%/%path:bar%', ['foo', 'bar']), 58 ('/', '/%foo%/%bar%', ['foo', ('bar', 'path')], ['foo', 'bar']),
35 ('/something', '/%foo%', ['foo']), 59 ('/something', '/%foo%', ['foo'], ['foo']),
36 ('/something', '/%path:foo%', ['foo']), 60 ('/something', '/%foo%', [('foo', 'path')], ['foo']),
37 ('/something', '/%foo%/%bar%', ['foo', 'bar']), 61 ('/something', '/%foo%/%bar%', ['foo', 'bar'], ['foo', 'bar']),
38 ('/something', '/%foo%/%path:bar%', ['foo', 'bar']), 62 ('/something', '/%foo%/%bar%', ['foo', ('bar', 'path')], ['foo', 'bar']),
39 ('/~johndoe', '/%foo%', ['foo']), 63 ('/~johndoe', '/%foo%', ['foo'], ['foo']),
40 ('/~johndoe', '/%path:foo%', ['foo']), 64 ('/~johndoe', '/%foo%', [('foo', 'path')], ['foo']),
41 ('/~johndoe', '/%foo%/%bar%', ['foo', 'bar']), 65 ('/~johndoe', '/%foo%/%bar%', ['foo', 'bar'], ['foo', 'bar']),
42 ('/~johndoe', '/%foo%/%path:bar%', ['foo', 'bar']) 66 ('/~johndoe', '/%foo%/%bar%', ['foo', ('bar', 'path')], ['foo', 'bar'])
43 ]) 67 ])
44 def test_required_metadata(site_root, route_pattern, 68 def test_required_metadata(site_root, route_pattern, params,
45 expected_func_parameters): 69 expected_func_parameters):
46 app = get_mock_app() 70 app = get_mock_app()
47 app.config.set('site/root', site_root.rstrip('/') + '/') 71 app.config.set('site/root', site_root.rstrip('/') + '/')
72 app.sources = [_getMockSource('blah', params)]
73
48 config = {'url': route_pattern, 'source': 'blah'} 74 config = {'url': route_pattern, 'source': 'blah'}
49 route = Route(app, config) 75 route = Route(app, config)
50 assert route.func_parameters == expected_func_parameters 76 assert route.uri_params == expected_func_parameters
51 77
52 78
53 @pytest.mark.parametrize( 79 @pytest.mark.parametrize(
54 'site_root, config, uri, expected_match', 80 'site_root, config, params, uri, expected_match',
55 [ 81 [
56 ('/', {'url': '/%foo%'}, 82 ('/', {'url': '/%foo%'},
83 ['foo'],
57 'something', 84 'something',
58 {'foo': 'something'}), 85 {'foo': 'something'}),
59 ('/', {'url': '/%foo%'}, 86 ('/', {'url': '/%foo%'},
87 ['foo'],
60 'something/other', 88 'something/other',
61 None), 89 None),
62 ('/', {'url': '/%path:foo%'}, 90 ('/', {'url': '/%foo%'},
63 'something/other', 91 [('foo', 'path')],
64 {'foo': 'something/other'}), 92 'something/other',
65 ('/', {'url': '/%path:foo%'}, 93 {'foo': 'something/other'}),
94 ('/', {'url': '/%foo%'},
95 [('foo', 'path')],
66 '', 96 '',
67 {'foo': ''}), 97 {'foo': ''}),
68 ('/', {'url': '/prefix/%path:foo%'}, 98 ('/', {'url': '/prefix/%foo%'},
99 [('foo', 'path')],
69 'prefix/something/other', 100 'prefix/something/other',
70 {'foo': 'something/other'}), 101 {'foo': 'something/other'}),
71 ('/', {'url': '/prefix/%path:foo%'}, 102 ('/', {'url': '/prefix/%foo%'},
103 [('foo', 'path')],
72 'prefix/', 104 'prefix/',
73 {'foo': ''}), 105 {'foo': ''}),
74 ('/', {'url': '/prefix/%path:foo%'}, 106 ('/', {'url': '/prefix/%foo%'},
107 [('foo', 'path')],
75 'prefix', 108 'prefix',
76 {'foo': ''}), 109 {'foo': ''}),
77 110
78 ('/blah', {'url': '/%foo%'}, 111 ('/blah', {'url': '/%foo%'},
112 ['foo'],
79 'something', 113 'something',
80 {'foo': 'something'}), 114 {'foo': 'something'}),
81 ('/blah', {'url': '/%foo%'}, 115 ('/blah', {'url': '/%foo%'},
116 ['foo'],
82 'something/other', 117 'something/other',
83 None), 118 None),
84 ('/blah', {'url': '/%path:foo%'}, 119 ('/blah', {'url': '/%foo%'},
85 'something/other', 120 [('foo', 'path')],
86 {'foo': 'something/other'}), 121 'something/other',
87 ('/blah', {'url': '/%path:foo%'}, 122 {'foo': 'something/other'}),
123 ('/blah', {'url': '/%foo%'},
124 [('foo', 'path')],
88 '', 125 '',
89 {'foo': ''}), 126 {'foo': ''}),
90 ('/blah', {'url': '/prefix/%path:foo%'}, 127 ('/blah', {'url': '/prefix/%foo%'},
128 [('foo', 'path')],
91 'prefix/something/other', 129 'prefix/something/other',
92 {'foo': 'something/other'}), 130 {'foo': 'something/other'}),
93 ('/blah', {'url': '/prefix/%path:foo%'}, 131 ('/blah', {'url': '/prefix/%foo%'},
132 [('foo', 'path')],
94 'prefix/', 133 'prefix/',
95 {'foo': ''}), 134 {'foo': ''}),
96 ('/blah', {'url': '/prefix/%path:foo%'}, 135 ('/blah', {'url': '/prefix/%foo%'},
136 [('foo', 'path')],
97 'prefix', 137 'prefix',
98 {'foo': ''}), 138 {'foo': ''}),
99 139
100 ('/~johndoe', {'url': '/%foo%'}, 140 ('/~johndoe', {'url': '/%foo%'},
141 ['foo'],
101 'something', 142 'something',
102 {'foo': 'something'}), 143 {'foo': 'something'}),
103 ('/~johndoe', {'url': '/%foo%'}, 144 ('/~johndoe', {'url': '/%foo%'},
145 ['foo'],
104 'something/other', 146 'something/other',
105 None), 147 None),
106 ('/~johndoe', {'url': '/%path:foo%'}, 148 ('/~johndoe', {'url': '/%foo%'},
107 'something/other', 149 [('foo', 'path')],
108 {'foo': 'something/other'}), 150 'something/other',
109 ('/~johndoe', {'url': '/%path:foo%'}, 151 {'foo': 'something/other'}),
152 ('/~johndoe', {'url': '/%foo%'},
153 [('foo', 'path')],
110 '', 154 '',
111 {'foo': ''}), 155 {'foo': ''}),
112 ('/~johndoe', {'url': '/prefix/%path:foo%'}, 156 ('/~johndoe', {'url': '/prefix/%foo%'},
157 [('foo', 'path')],
113 'prefix/something/other', 158 'prefix/something/other',
114 {'foo': 'something/other'}), 159 {'foo': 'something/other'}),
115 ('/~johndoe', {'url': '/prefix/%path:foo%'}, 160 ('/~johndoe', {'url': '/prefix/%foo%'},
161 [('foo', 'path')],
116 'prefix/', 162 'prefix/',
117 {'foo': ''}), 163 {'foo': ''}),
118 ('/~johndoe', {'url': '/prefix/%path:foo%'}, 164 ('/~johndoe', {'url': '/prefix/%foo%'},
165 [('foo', 'path')],
119 'prefix', 166 'prefix',
120 {'foo': ''}), 167 {'foo': ''}),
121 ]) 168 ])
122 def test_match_uri(site_root, config, uri, expected_match): 169 def test_match_uri(site_root, config, params, uri, expected_match):
123 site_root = site_root.rstrip('/') + '/' 170 site_root = site_root.rstrip('/') + '/'
124 app = get_mock_app() 171 app = get_mock_app()
125 app.config.set('site/root', urllib.parse.quote(site_root)) 172 app.config.set('site/root', urllib.parse.quote(site_root))
173 app.sources = [_getMockSource('blah', params)]
174
126 config.setdefault('source', 'blah') 175 config.setdefault('source', 'blah')
127 route = Route(app, config) 176 route = Route(app, config)
128 assert route.uri_pattern == config['url'].lstrip('/') 177 assert route.uri_pattern == config['url'].lstrip('/')
129 m = route.matchUri(urllib.parse.quote(site_root) + uri) 178 m = route.matchUri(urllib.parse.quote(site_root) + uri)
130 assert m == expected_match 179 assert m == expected_match
131 180
132 181
133 @pytest.mark.parametrize( 182 @pytest.mark.parametrize(
134 'site_root', 183 'site_root',
135 [ 184 [
136 ('/'), ('/whatever'), ('/~johndoe') 185 ('/'),
186 ('/whatever'),
187 ('/~johndoe')
137 ]) 188 ])
138 def test_match_uri_requires_absolute_uri(site_root): 189 def test_match_uri_requires_absolute_uri(site_root):
139 with pytest.raises(Exception): 190 with pytest.raises(Exception):
140 app = get_mock_app() 191 app = get_mock_app()
141 app.config.set('site/root', site_root.rstrip('/') + '/') 192 app.config.set('site/root', site_root.rstrip('/') + '/')
142 config = {'url': '/%path:slug%', 'source': 'blah'} 193 app.sources = [_getMockSource('blah', [('slug', 'path')])]
194
195 config = {'url': '/%slug%', 'source': 'blah'}
143 route = Route(app, config) 196 route = Route(app, config)
144 route.matchUri('notabsuri') 197 route.matchUri('notabsuri')
145 198
146 199
147 @pytest.mark.parametrize( 200 @pytest.mark.parametrize(
179 app = get_mock_app() 232 app = get_mock_app()
180 app.config.set('site/root', urllib.parse.quote(root)) 233 app.config.set('site/root', urllib.parse.quote(root))
181 app.config.set('site/pretty_urls', pretty) 234 app.config.set('site/pretty_urls', pretty)
182 app.config.set('site/trailing_slash', False) 235 app.config.set('site/trailing_slash', False)
183 app.config.set('__cache/pagination_suffix_format', '/%(num)d') 236 app.config.set('__cache/pagination_suffix_format', '/%(num)d')
184 237 app.sources = [_getMockSource('blah', [('slug', 'path')])]
185 config = {'url': '/%path:slug%', 'source': 'blah'} 238
239 config = {'url': '/%slug%', 'source': 'blah'}
186 route = Route(app, config) 240 route = Route(app, config)
187 uri = route.getUri({'slug': slug}, sub_num=page_num) 241 uri = route.getUri({'slug': slug}, sub_num=page_num)
188 assert uri == (urllib.parse.quote(root) + expected) 242 assert uri == (urllib.parse.quote(root) + expected)
189 243