Mercurial > piecrust2
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 |
