1# -*- coding: utf-8 -*- 2import random 3 4import webapp2 5from webapp2 import BaseRoute, RedirectHandler, Request, Route, Router 6 7import test_base 8 9 10class TestRoute(test_base.BaseTestCase): 11 def test_no_variable(self): 12 route = Route(r'/hello', None) 13 route, args, kwargs = route.match(Request.blank('/hello')) 14 self.assertEqual(kwargs, {}) 15 url = route.build(Request.blank('/'), (), {}) 16 self.assertEqual(url, '/hello') 17 18 route = Route(r'/hello/world/', None) 19 route, args, kwargs = route.match(Request.blank('/hello/world/')) 20 self.assertEqual(kwargs, {}) 21 url = route.build(Request.blank('/'), (), {}) 22 self.assertEqual(url, '/hello/world/') 23 24 def test_repetition_operator(self): 25 route = Route(r'/<:\d>', None) 26 self.assertEqual(route.match(Request.blank('/1')), (route, ('1',), {})) 27 self.assertEqual(route.match(Request.blank('/2')), (route, ('2',), {})) 28 29 route = Route(r'/<:\d{2,3}>', None) 30 self.assertEqual(route.match(Request.blank('/11')), (route, ('11',), {})) 31 self.assertEqual(route.match(Request.blank('/111')), (route, ('111',), {})) 32 self.assertEqual(route.match(Request.blank('/1111')), None) 33 34 def test_unnamed_variable(self): 35 route = Route(r'/<:\d{4}>', None) 36 self.assertEqual(route.match(Request.blank('/2010')), (route, ('2010',), {})) 37 self.assertEqual(route.match(Request.blank('/aaaa')), None) 38 39 route = Route(r'/<:\d{2}>.<:\d{2}>', None) 40 self.assertEqual(route.match(Request.blank('/98.99')), (route, ('98', '99'), {})) 41 self.assertEqual(route.match(Request.blank('/aa.aa')), None) 42 43 route = Route(r'/<:\d{2}>.<:\d{2}>/<foo>', None) 44 self.assertEqual(route.match(Request.blank('/98.99/test')), (route, ('98', '99'), {'foo': 'test'})) 45 self.assertEqual(route.match(Request.blank('/aa.aa/test')), None) 46 47 def test_simple_variable(self): 48 route = Route(r'/<foo>', None) 49 self.assertEqual(route.match(Request.blank('/bar')), (route, (), {'foo': 'bar'})) 50 url = route.build(Request.blank('/'), (), dict(foo='baz')) 51 self.assertEqual(url, '/baz') 52 53 def test_expr_variable(self): 54 route = Route(r'/<year:\d{4}>', None) 55 self.assertEqual(route.match(Request.blank('/bar')), None) 56 self.assertEqual(route.match(Request.blank('/2010')), (route, (), {'year': '2010'})) 57 self.assertEqual(route.match(Request.blank('/1900')), (route, (), {'year': '1900'})) 58 url = route.build(Request.blank('/'), (), dict(year='2010')) 59 self.assertEqual(url, '/2010') 60 61 def test_expr_variable2(self): 62 route = Route(r'/<year:\d{4}>/foo/', None) 63 url = route.build(Request.blank('/'), (), dict(year='2010')) 64 self.assertEqual(url, '/2010/foo/') 65 66 def test_build_missing_argument(self): 67 route = Route(r'/<:\d{4}>', None) 68 self.assertRaises(KeyError, route.build, Request.blank('/'), (), {}) 69 70 route = Route(r'/<:\d{4}>/<:\d{2}>', None) 71 self.assertRaises(KeyError, route.build, Request.blank('/'), (2010,), {}) 72 73 def test_build_invalid_argument(self): 74 route = Route(r'/<:\d{4}>', None) 75 self.assertRaises(ValueError, route.build, Request.blank('/'), ('20100',), {}) 76 77 def test_build_invalid_argument2(self): 78 route = Route(r'/<:\d{4}>', None) 79 self.assertRaises(ValueError, route.build, Request.blank('/'), ('201a',), {}) 80 81 def test_build_missing_keyword(self): 82 route = Route(r'/<year:\d{4}>', None) 83 self.assertRaises(KeyError, route.build, Request.blank('/'), (), {}) 84 85 def test_build_missing_keyword2(self): 86 route = Route(r'/<year:\d{4}>/<month:\d{2}>', None) 87 self.assertRaises(KeyError, route.build, Request.blank('/'), (), dict(year='2010')) 88 89 def test_build_invalid_keyword(self): 90 route = Route(r'/<year:\d{4}>', None) 91 self.assertRaises(ValueError, route.build, Request.blank('/'), (), dict(year='20100')) 92 93 def test_build_invalid_keyword2(self): 94 route = Route(r'/<year:\d{4}>', None) 95 self.assertRaises(ValueError, route.build, Request.blank('/'), (), dict(year='201a')) 96 97 def test_build_with_unnamed_variable(self): 98 route = Route(r'/<:\d{4}>/<month:\d{2}>', None) 99 100 url = route.build(Request.blank('/'), (2010,), dict(month=10)) 101 self.assertEqual(url, '/2010/10') 102 103 url = route.build(Request.blank('/'), ('1999',), dict(month='07')) 104 self.assertEqual(url, '/1999/07') 105 106 def test_build_default_keyword(self): 107 route = Route(r'/<year:\d{4}>/<month:\d{2}>', None, 108 defaults={'month': 10}) 109 url = route.build(Request.blank('/'), (), dict(year='2010')) 110 self.assertEqual(url, '/2010/10') 111 112 route = Route(r'/<year:\d{4}>/<month:\d{2}>', None, 113 defaults={'year': 1900}) 114 url = route.build(Request.blank('/'), (), dict(month='07')) 115 self.assertEqual(url, '/1900/07') 116 117 def test_build_extra_keyword(self): 118 route = Route(r'/<year:\d{4}>', None) 119 url = route.build(Request.blank('/'), (), dict(year='2010', foo='bar')) 120 self.assertEqual(url, '/2010?foo=bar') 121 # Arguments are sorted. 122 url = route.build(Request.blank('/'), (), dict(year='2010', foo='bar', baz='ding')) 123 self.assertEqual(url, '/2010?baz=ding&foo=bar') 124 125 def test_build_extra_positional_keyword(self): 126 route = Route(r'/<year:\d{4}>/<:\d{2}>', None) 127 128 url = route.build(Request.blank('/'), ('08', 'i-should-be-ignored', 'me-too'), dict(year='2010', foo='bar')) 129 self.assertEqual(url, '/2010/08?foo=bar') 130 131 url = route.build(Request.blank('/'), ('08', 'i-should-be-ignored', 'me-too'), dict(year='2010', foo='bar', baz='ding')) 132 self.assertEqual(url, '/2010/08?baz=ding&foo=bar') 133 134 def test_build_int_keyword(self): 135 route = Route(r'/<year:\d{4}>', None) 136 url = route.build(Request.blank('/'), (), dict(year=2010)) 137 self.assertEqual(url, '/2010') 138 139 def test_build_int_variable(self): 140 route = Route(r'/<:\d{4}>', None) 141 url = route.build(Request.blank('/'), (2010,), {}) 142 self.assertEqual(url, '/2010') 143 144 def test_router_build_error(self): 145 router = Router(None) 146 router.add(Route('/<year:\d{4}>', None, name='year-page')) 147 148 url = router.build(Request.blank('/'), 'year-page', (), dict(year='2010')) 149 self.assertEqual(url, '/2010') 150 151 self.assertRaises(KeyError, router.build, Request.blank('/'), 'i-dont-exist', (), dict(year='2010')) 152 153 def test_reverse_template(self): 154 route = Route('/foo', None) 155 # Access route.regex just to set the lazy properties. 156 regex = route.regex 157 self.assertEqual(route.reverse_template, '/foo') 158 159 route = Route('/foo/<bar>', None) 160 # Access route.regex just to set the lazy properties. 161 regex = route.regex 162 self.assertEqual(route.reverse_template, '/foo/%(bar)s') 163 164 route = Route('/foo/<bar>/<baz:\d>', None) 165 # Access route.regex just to set the lazy properties. 166 regex = route.regex 167 self.assertEqual(route.reverse_template, '/foo/%(bar)s/%(baz)s') 168 169 def test_invalid_template(self): 170 # To break it: 171 # <>foo:><bar<:baz> 172 route = Route('/<foo/<:bar', None) 173 # Access route.regex just to set the lazy properties. 174 regex = route.regex 175 self.assertEqual(route.reverse_template, '/<foo/<:bar') 176 177 def test_build_full_without_request(self): 178 router = Router(None) 179 router.add(Route(r'/hello', None, name='hello')) 180 self.assertRaises(AttributeError, router.build, None, 'hello', (), dict(_full=True)) 181 self.assertRaises(AttributeError, router.build, None, 'hello', (), dict(_scheme='https')) 182 183 def test_positions(self): 184 template = '/<:\d+>' * 98 185 args = tuple(str(i) for i in range(98)) 186 url_res = '/' + '/'.join(args) 187 188 route = Route(template, None) 189 self.assertEqual(route.match(Request.blank(url_res)), (route, args, {})) 190 url = route.build(Request.blank('/'), args, {}) 191 self.assertEqual(url_res, url) 192 193 args = [str(i) for i in range(1000)] 194 random.shuffle(args) 195 args = tuple(args[:98]) 196 url_res = '/' + '/'.join(args) 197 self.assertEqual(route.match(Request.blank(url_res)), (route, args, {})) 198 url = route.build(Request.blank('/'), args, {}) 199 self.assertEqual(url_res, url) 200 201 def test_build_only_without_name(self): 202 self.assertRaises(ValueError, Route, r'/<foo>', None, build_only=True) 203 204 def test_route_repr(self): 205 self.assertEqual(Route(r'/<foo>', None).__repr__(), 206 "<Route('/<foo>', None, name=None, defaults={}, build_only=False)>") 207 self.assertEqual(Route(r'/<foo>', None, name='bar', defaults={'baz': 'ding'}, build_only=True).__repr__(), 208 "<Route('/<foo>', None, name='bar', defaults={'baz': 'ding'}, build_only=True)>") 209 210 self.assertEqual(str(Route(r'/<foo>', None)), 211 "<Route('/<foo>', None, name=None, defaults={}, build_only=False)>") 212 self.assertEqual(str(Route(r'/<foo>', None, name='bar', defaults={'baz': 'ding'}, build_only=True)), 213 "<Route('/<foo>', None, name='bar', defaults={'baz': 'ding'}, build_only=True)>") 214 215 def test_router_repr(self): 216 router = Router(None) 217 router.add(Route(r'/hello', None, name='hello', build_only=True)) 218 router.add(Route(r'/world', None)) 219 220 self.assertEqual(router.__repr__(), "<Router([<Route('/world', None, name=None, defaults={}, build_only=False)>, <Route('/hello', None, name='hello', defaults={}, build_only=True)>])>") 221 222 def test_base_route(self): 223 route = BaseRoute('foo', 'bar') 224 self.assertRaises(NotImplementedError, route.match, None) 225 226 def test_set_matcher(self): 227 req = Request.blank('/') 228 def custom_matcher(router, request): 229 self.assertEqual(request, req) 230 231 router = Router(None) 232 router.set_matcher(custom_matcher) 233 router.match(req) 234 235 def test_set_builder(self): 236 req = Request.blank('/') 237 def custom_builder(router, request, name, args, kwargs): 238 self.assertEqual(request, req) 239 return 'http://www.google.com' 240 241 router = Router(None) 242 router.set_builder(custom_builder) 243 res = router.build(req, '', (), {}) 244 self.assertEqual(res, 'http://www.google.com') 245 246 def test_set_adapter(self): 247 def custom_adapter(router, handler): 248 class MyAdapter(webapp2.BaseHandlerAdapter): 249 def __call__(self, request, response): 250 response.write('hello my adapter') 251 252 return MyAdapter(handler) 253 254 def myhandler(request, *args, **kwargs): 255 return webapp2.Response('hello') 256 257 app = webapp2.WSGIApplication([('/', myhandler)]) 258 app.router.set_adapter(custom_adapter) 259 260 rsp = app.get_response('/') 261 self.assertEqual(rsp.status_int, 200) 262 self.assertEqual(rsp.body, 'hello my adapter') 263 264 def test_methods(self): 265 route = Route(r'/', methods=['GET', 'POST']) 266 router = Router([route]) 267 req = Request.blank('/') 268 req.method = 'GET' 269 self.assertTrue(router.match(req) is not None) 270 req.method = 'POST' 271 self.assertTrue(router.match(req) is not None) 272 req.method = 'PUT' 273 self.assertRaises(webapp2.exc.HTTPMethodNotAllowed, router.match, req) 274 275 def test_schemes(self): 276 route = Route(r'/', schemes=['http']) 277 req = Request.blank('http://mydomain.com/') 278 self.assertTrue(route.match(req) is not None) 279 req = Request.blank('https://mydomain.com/') 280 self.assertTrue(route.match(req) is None) 281 282 route = Route(r'/', schemes=['https']) 283 req = Request.blank('https://mydomain.com/') 284 self.assertTrue(route.match(req) is not None) 285 req = Request.blank('http://mydomain.com/') 286 self.assertTrue(route.match(req) is None) 287 288 289class TestSimpleRoute(test_base.BaseTestCase): 290 def test_no_variable(self): 291 router = webapp2.Router([(r'/', 'my_handler')]) 292 293 matched_route, args, kwargs = router.match(webapp2.Request.blank('/')) 294 self.assertEqual(args, ()) 295 self.assertEqual(kwargs, {}) 296 297 def test_simple_variables(self): 298 router = webapp2.Router([(r'/(\d{4})/(\d{2})', 'my_handler')]) 299 300 matched_route, args, kwargs = router.match(webapp2.Request.blank('/2007/10')) 301 self.assertEqual(args, ('2007', '10')) 302 self.assertEqual(kwargs, {}) 303 304 def test_build(self): 305 route = webapp2.SimpleRoute('/', None) 306 self.assertRaises(NotImplementedError, route.build, None, None, None) 307 308 def test_route_repr(self): 309 self.assertEqual(webapp2.SimpleRoute(r'/<foo>', None).__repr__(), "<SimpleRoute('/<foo>', None)>") 310 self.assertEqual(str(webapp2.SimpleRoute(r'/<foo>', None)), "<SimpleRoute('/<foo>', None)>") 311 312 313if __name__ == '__main__': 314 test_base.main() 315