1# -*- coding: utf-8 -*-
2"""
3Tests for webapp2 webapp2.RequestHandler
4"""
5import os
6import StringIO
7import sys
8import urllib
9
10import webapp2
11
12import test_base
13
14
15class BareHandler(object):
16    def __init__(self, request, response):
17        self.response = response
18        response.write('I am not a RequestHandler but I work.')
19
20    def dispatch(self):
21        return self.response
22
23
24class HomeHandler(webapp2.RequestHandler):
25    def get(self, **kwargs):
26        self.response.out.write('home sweet home')
27
28    def post(self, **kwargs):
29        self.response.out.write('home sweet home - POST')
30
31
32class MethodsHandler(HomeHandler):
33    def put(self, **kwargs):
34        self.response.out.write('home sweet home - PUT')
35
36    def delete(self, **kwargs):
37        self.response.out.write('home sweet home - DELETE')
38
39    def head(self, **kwargs):
40        self.response.out.write('home sweet home - HEAD')
41
42    def trace(self, **kwargs):
43        self.response.out.write('home sweet home - TRACE')
44
45    def options(self, **kwargs):
46        self.response.out.write('home sweet home - OPTIONS')
47
48
49class RedirectToHandler(webapp2.RequestHandler):
50    def get(self, **kwargs):
51        return self.redirect_to('route-test', _fragment='my-anchor', year='2010',
52                                month='07', name='test', foo='bar')
53
54
55class RedirectAbortHandler(webapp2.RequestHandler):
56    def get(self, **kwargs):
57        self.redirect('/somewhere', abort=True)
58
59
60class BrokenHandler(webapp2.RequestHandler):
61    def get(self, **kwargs):
62        raise ValueError('booo!')
63
64
65class BrokenButFixedHandler(BrokenHandler):
66    def handle_exception(self, exception, debug_mode):
67        # Let's fix it.
68        self.response.set_status(200)
69        self.response.out.write('that was close!')
70
71
72def handle_404(request, response, exception):
73    response.out.write('404 custom handler')
74    response.set_status(404)
75
76
77def handle_405(request, response, exception):
78    response.out.write('405 custom handler')
79    response.set_status(405, 'Custom Error Message')
80    response.headers['Allow'] = 'GET'
81
82
83def handle_500(request, response, exception):
84    response.out.write('500 custom handler')
85    response.set_status(500)
86
87
88class PositionalHandler(webapp2.RequestHandler):
89    def get(self, month, day, slug=None):
90        self.response.out.write('%s:%s:%s' % (month, day, slug))
91
92
93class HandlerWithError(webapp2.RequestHandler):
94    def get(self, **kwargs):
95        self.response.out.write('bla bla bla bla bla bla')
96        self.error(403)
97
98
99class InitializeHandler(webapp2.RequestHandler):
100    def __init__(self):
101        pass
102
103    def get(self):
104        self.response.out.write('Request method: %s' % self.request.method)
105
106
107class WebDavHandler(webapp2.RequestHandler):
108    def version_control(self):
109        self.response.out.write('Method: VERSION-CONTROL')
110
111    def unlock(self):
112        self.response.out.write('Method: UNLOCK')
113
114    def propfind(self):
115        self.response.out.write('Method: PROPFIND')
116
117
118class AuthorizationHandler(webapp2.RequestHandler):
119    def get(self):
120        self.response.out.write('nothing here')
121
122class HandlerWithEscapedArg(webapp2.RequestHandler):
123    def get(self, name):
124        self.response.out.write(urllib.unquote_plus(name))
125
126def get_redirect_url(handler, **kwargs):
127    return handler.uri_for('methods')
128
129
130app = webapp2.WSGIApplication([
131    ('/bare', BareHandler),
132    webapp2.Route('/', HomeHandler, name='home'),
133    webapp2.Route('/methods', MethodsHandler, name='methods'),
134    webapp2.Route('/broken', BrokenHandler),
135    webapp2.Route('/broken-but-fixed', BrokenButFixedHandler),
136    webapp2.Route('/<year:\d{4}>/<month:\d{1,2}>/<name>', None, name='route-test'),
137    webapp2.Route('/<:\d\d>/<:\d{2}>/<:\w+>', PositionalHandler, name='positional'),
138    webapp2.Route('/redirect-me', webapp2.RedirectHandler, defaults={'_uri': '/broken'}),
139    webapp2.Route('/redirect-me2', webapp2.RedirectHandler, defaults={'_uri': get_redirect_url}),
140    webapp2.Route('/redirect-me3', webapp2.RedirectHandler, defaults={'_uri': '/broken', '_permanent': False}),
141    webapp2.Route('/redirect-me4', webapp2.RedirectHandler, defaults={'_uri': get_redirect_url, '_permanent': False}),
142    webapp2.Route('/redirect-me5', RedirectToHandler),
143    webapp2.Route('/redirect-me6', RedirectAbortHandler),
144    webapp2.Route('/lazy', 'resources.handlers.LazyHandler'),
145    webapp2.Route('/error', HandlerWithError),
146    webapp2.Route('/initialize', InitializeHandler),
147    webapp2.Route('/webdav', WebDavHandler),
148    webapp2.Route('/authorization', AuthorizationHandler),
149    webapp2.Route('/escape/<name:.*>', HandlerWithEscapedArg, 'escape'),
150], debug=False)
151
152DEFAULT_RESPONSE = """Status: 404 Not Found
153content-type: text/html; charset=utf8
154Content-Length: 52
155
156404 Not Found
157
158The resource could not be found.
159
160   """
161
162class TestHandler(test_base.BaseTestCase):
163    def tearDown(self):
164        super(TestHandler, self).tearDown()
165        app.error_handlers = {}
166
167    def test_200(self):
168        rsp = app.get_response('/')
169        self.assertEqual(rsp.status_int, 200)
170        self.assertEqual(rsp.body, 'home sweet home')
171
172    def test_404(self):
173        req = webapp2.Request.blank('/nowhere')
174        rsp = req.get_response(app)
175        self.assertEqual(rsp.status_int, 404)
176
177    def test_405(self):
178        req = webapp2.Request.blank('/')
179        req.method = 'PUT'
180        rsp = req.get_response(app)
181        self.assertEqual(rsp.status_int, 405)
182        self.assertEqual(rsp.headers.get('Allow'), 'GET, POST')
183
184    def test_500(self):
185        req = webapp2.Request.blank('/broken')
186        rsp = req.get_response(app)
187        self.assertEqual(rsp.status_int, 500)
188
189    def test_500_but_fixed(self):
190        req = webapp2.Request.blank('/broken-but-fixed')
191        rsp = req.get_response(app)
192        self.assertEqual(rsp.status_int, 200)
193        self.assertEqual(rsp.body, 'that was close!')
194
195    def test_501(self):
196        # 501 Not Implemented
197        req = webapp2.Request.blank('/methods')
198        req.method = 'FOOBAR'
199        rsp = req.get_response(app)
200        self.assertEqual(rsp.status_int, 501)
201
202    def test_lazy_handler(self):
203        req = webapp2.Request.blank('/lazy')
204        rsp = req.get_response(app)
205        self.assertEqual(rsp.status_int, 200)
206        self.assertEqual(rsp.body, 'I am a laaazy view.')
207
208    def test_handler_with_error(self):
209        req = webapp2.Request.blank('/error')
210        rsp = req.get_response(app)
211        self.assertEqual(rsp.status_int, 403)
212        self.assertEqual(rsp.body, '')
213
214    def test_debug_mode(self):
215        app = webapp2.WSGIApplication([
216            webapp2.Route('/broken', BrokenHandler),
217        ], debug=True)
218        req = webapp2.Request.blank('/broken')
219        rsp = req.get_response(app)
220        self.assertEqual(rsp.status_int, 500)
221
222    def test_custom_error_handlers(self):
223        app.error_handlers = {
224            404: handle_404,
225            405: handle_405,
226            500: handle_500,
227        }
228        req = webapp2.Request.blank('/nowhere')
229        rsp = req.get_response(app)
230        self.assertEqual(rsp.status_int, 404)
231        self.assertEqual(rsp.body, '404 custom handler')
232
233        req = webapp2.Request.blank('/')
234        req.method = 'PUT'
235        rsp = req.get_response(app)
236        self.assertEqual(rsp.status, '405 Custom Error Message')
237        self.assertEqual(rsp.body, '405 custom handler')
238        self.assertEqual(rsp.headers.get('Allow'), 'GET')
239
240        req = webapp2.Request.blank('/broken')
241        rsp = req.get_response(app)
242        self.assertEqual(rsp.status_int, 500)
243        self.assertEqual(rsp.body, '500 custom handler')
244
245    def test_methods(self):
246        app.debug = True
247        req = webapp2.Request.blank('/methods')
248        rsp = req.get_response(app)
249        self.assertEqual(rsp.status_int, 200)
250        self.assertEqual(rsp.body, 'home sweet home')
251
252        req = webapp2.Request.blank('/methods')
253        req.method = 'POST'
254        rsp = req.get_response(app)
255        self.assertEqual(rsp.status_int, 200)
256        self.assertEqual(rsp.body, 'home sweet home - POST')
257
258        req = webapp2.Request.blank('/methods')
259        req.method = 'PUT'
260        rsp = req.get_response(app)
261        self.assertEqual(rsp.status_int, 200)
262        self.assertEqual(rsp.body, 'home sweet home - PUT')
263
264        req = webapp2.Request.blank('/methods')
265        req.method = 'DELETE'
266        rsp = req.get_response(app)
267        self.assertEqual(rsp.status_int, 200)
268        self.assertEqual(rsp.body, 'home sweet home - DELETE')
269
270        req = webapp2.Request.blank('/methods')
271        req.method = 'HEAD'
272        rsp = req.get_response(app)
273        self.assertEqual(rsp.status_int, 200)
274        self.assertEqual(rsp.body, '')
275
276        req = webapp2.Request.blank('/methods')
277        req.method = 'OPTIONS'
278        rsp = req.get_response(app)
279        self.assertEqual(rsp.status_int, 200)
280        self.assertEqual(rsp.body, 'home sweet home - OPTIONS')
281
282        req = webapp2.Request.blank('/methods')
283        req.method = 'TRACE'
284        rsp = req.get_response(app)
285        self.assertEqual(rsp.status_int, 200)
286        self.assertEqual(rsp.body, 'home sweet home - TRACE')
287        app.debug = False
288
289    def test_positional(self):
290        req = webapp2.Request.blank('/07/31/test')
291        rsp = req.get_response(app)
292        self.assertEqual(rsp.status_int, 200)
293        self.assertEqual(rsp.body, '07:31:test')
294
295        req = webapp2.Request.blank('/10/18/wooohooo')
296        rsp = req.get_response(app)
297        self.assertEqual(rsp.status_int, 200)
298        self.assertEqual(rsp.body, '10:18:wooohooo')
299
300    def test_redirect(self):
301        req = webapp2.Request.blank('/redirect-me')
302        rsp = req.get_response(app)
303        self.assertEqual(rsp.status_int, 301)
304        self.assertEqual(rsp.body, '')
305        self.assertEqual(rsp.headers['Location'], 'http://localhost/broken')
306
307    def test_redirect_with_callable(self):
308        req = webapp2.Request.blank('/redirect-me2')
309        rsp = req.get_response(app)
310        self.assertEqual(rsp.status_int, 301)
311        self.assertEqual(rsp.body, '')
312        self.assertEqual(rsp.headers['Location'], 'http://localhost/methods')
313
314    def test_redirect_not_permanent(self):
315        req = webapp2.Request.blank('/redirect-me3')
316        rsp = req.get_response(app)
317        self.assertEqual(rsp.status_int, 302)
318        self.assertEqual(rsp.body, '')
319        self.assertEqual(rsp.headers['Location'], 'http://localhost/broken')
320
321    def test_redirect_with_callable_not_permanent(self):
322        req = webapp2.Request.blank('/redirect-me4')
323        rsp = req.get_response(app)
324        self.assertEqual(rsp.status_int, 302)
325        self.assertEqual(rsp.body, '')
326        self.assertEqual(rsp.headers['Location'], 'http://localhost/methods')
327
328    def test_redirect_to(self):
329        req = webapp2.Request.blank('/redirect-me5')
330        rsp = req.get_response(app)
331        self.assertEqual(rsp.status_int, 302)
332        self.assertEqual(rsp.body, '')
333        self.assertEqual(rsp.headers['Location'], 'http://localhost/2010/07/test?foo=bar#my-anchor')
334
335    def test_redirect_abort(self):
336        req = webapp2.Request.blank('/redirect-me6')
337        rsp = req.get_response(app)
338        self.assertEqual(rsp.status_int, 302)
339        self.assertEqual(rsp.body, """302 Moved Temporarily
340
341The resource was found at http://localhost/somewhere; you should be redirected automatically.  """)
342        self.assertEqual(rsp.headers['Location'], 'http://localhost/somewhere')
343
344    def test_run(self):
345        os.environ['REQUEST_METHOD'] = 'GET'
346
347        app.run()
348        #self.assertEqual(sys.stdout.read(), DEFAULT_RESPONSE)
349
350    def test_run_bare(self):
351        os.environ['REQUEST_METHOD'] = 'GET'
352        app.run(bare=True)
353
354        #self.assertEqual(sys.stdout.read(), DEFAULT_RESPONSE)
355
356    def test_run_debug(self):
357        debug = app.debug
358        app.debug = True
359        os.environ['REQUEST_METHOD'] = 'GET'
360        os.environ['PATH_INFO'] = '/'
361
362        res = app.run(bare=True)
363        #self.assertEqual(sys.stdout.read(), DEFAULT_RESPONSE)
364
365        app.debug = debug
366
367    '''
368    def test_get_valid_methods(self):
369        req = webapp2.Request.blank('http://localhost:80/')
370        req.app = app
371        app.set_globals(app=app, request=req)
372
373        handler = BrokenHandler(req, None)
374        handler.app = app
375        self.assertEqual(handler.get_valid_methods().sort(), ['GET'].sort())
376
377        handler = HomeHandler(req, None)
378        handler.app = app
379        self.assertEqual(handler.get_valid_methods().sort(),
380            ['GET', 'POST'].sort())
381
382        handler = MethodsHandler(req, None)
383        handler.app = app
384        self.assertEqual(handler.get_valid_methods().sort(),
385            ['GET', 'POST', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'].sort())
386    '''
387
388    def test_uri_for(self):
389        class Handler(webapp2.RequestHandler):
390            def get(self, *args, **kwargs):
391                pass
392
393        req = webapp2.Request.blank('http://localhost:80/')
394        req.route = webapp2.Route('')
395        req.route_args = tuple()
396        req.route_kwargs = {}
397        req.app = app
398        app.set_globals(app=app, request=req)
399        handler = Handler(req, webapp2.Response())
400        handler.app = app
401
402        for func in (handler.uri_for,):
403            self.assertEqual(func('home'), '/')
404            self.assertEqual(func('home', foo='bar'), '/?foo=bar')
405            self.assertEqual(func('home', _fragment='my-anchor', foo='bar'), '/?foo=bar#my-anchor')
406            self.assertEqual(func('home', _fragment='my-anchor'), '/#my-anchor')
407            self.assertEqual(func('home', _full=True), 'http://localhost:80/')
408            self.assertEqual(func('home', _full=True, _fragment='my-anchor'), 'http://localhost:80/#my-anchor')
409            self.assertEqual(func('home', _scheme='https'), 'https://localhost:80/')
410            self.assertEqual(func('home', _scheme='https', _full=False), 'https://localhost:80/')
411            self.assertEqual(func('home', _scheme='https', _fragment='my-anchor'), 'https://localhost:80/#my-anchor')
412
413            self.assertEqual(func('methods'), '/methods')
414            self.assertEqual(func('methods', foo='bar'), '/methods?foo=bar')
415            self.assertEqual(func('methods', _fragment='my-anchor', foo='bar'), '/methods?foo=bar#my-anchor')
416            self.assertEqual(func('methods', _fragment='my-anchor'), '/methods#my-anchor')
417            self.assertEqual(func('methods', _full=True), 'http://localhost:80/methods')
418            self.assertEqual(func('methods', _full=True, _fragment='my-anchor'), 'http://localhost:80/methods#my-anchor')
419            self.assertEqual(func('methods', _scheme='https'), 'https://localhost:80/methods')
420            self.assertEqual(func('methods', _scheme='https', _full=False), 'https://localhost:80/methods')
421            self.assertEqual(func('methods', _scheme='https', _fragment='my-anchor'), 'https://localhost:80/methods#my-anchor')
422
423            self.assertEqual(func('route-test', year='2010', month='0', name='test'), '/2010/0/test')
424            self.assertEqual(func('route-test', year='2010', month='07', name='test'), '/2010/07/test')
425            self.assertEqual(func('route-test', year='2010', month='07', name='test', foo='bar'), '/2010/07/test?foo=bar')
426            self.assertEqual(func('route-test', _fragment='my-anchor', year='2010', month='07', name='test', foo='bar'), '/2010/07/test?foo=bar#my-anchor')
427            self.assertEqual(func('route-test', _fragment='my-anchor', year='2010', month='07', name='test'), '/2010/07/test#my-anchor')
428            self.assertEqual(func('route-test', _full=True, year='2010', month='07', name='test'), 'http://localhost:80/2010/07/test')
429            self.assertEqual(func('route-test', _full=True, _fragment='my-anchor', year='2010', month='07', name='test'), 'http://localhost:80/2010/07/test#my-anchor')
430            self.assertEqual(func('route-test', _scheme='https', year='2010', month='07', name='test'), 'https://localhost:80/2010/07/test')
431            self.assertEqual(func('route-test', _scheme='https', _full=False, year='2010', month='07', name='test'), 'https://localhost:80/2010/07/test')
432            self.assertEqual(func('route-test', _scheme='https', _fragment='my-anchor', year='2010', month='07', name='test'), 'https://localhost:80/2010/07/test#my-anchor')
433
434    def test_extra_request_methods(self):
435        allowed_methods_backup = app.allowed_methods
436        webdav_methods = ('VERSION-CONTROL', 'UNLOCK', 'PROPFIND')
437
438        for method in webdav_methods:
439            # It is still not possible to use WebDav methods...
440            req = webapp2.Request.blank('/webdav')
441            req.method = method
442            rsp = req.get_response(app)
443            self.assertEqual(rsp.status_int, 501)
444
445        # Let's extend ALLOWED_METHODS with some WebDav methods.
446        app.allowed_methods = tuple(app.allowed_methods) + webdav_methods
447
448        #self.assertEqual(sorted(webapp2.get_valid_methods(WebDavHandler)), sorted(list(webdav_methods)))
449
450        # Now we can use WebDav methods...
451        for method in webdav_methods:
452            req = webapp2.Request.blank('/webdav')
453            req.method = method
454            rsp = req.get_response(app)
455            self.assertEqual(rsp.status_int, 200)
456            self.assertEqual(rsp.body, 'Method: %s' % method)
457
458        # Restore initial values.
459        app.allowed_methods = allowed_methods_backup
460        self.assertEqual(len(app.allowed_methods), 7)
461
462    def test_escaping(self):
463        def get_req(uri):
464            req = webapp2.Request.blank(uri)
465            app.set_globals(app=app, request=req)
466            handler = webapp2.RequestHandler(req, None)
467            handler.app = req.app = app
468            return req, handler
469
470        req, handler = get_req('http://localhost:80/')
471        uri = webapp2.uri_for('escape', name='with space')
472        req, handler = get_req(uri)
473        rsp = req.get_response(app)
474        self.assertEqual(rsp.status_int, 200)
475        self.assertEqual(rsp.body, 'with space')
476
477        req, handler = get_req('http://localhost:80/')
478        uri = webapp2.uri_for('escape', name='with+plus')
479        req, handler = get_req(uri)
480        rsp = req.get_response(app)
481        self.assertEqual(rsp.status_int, 200)
482        self.assertEqual(rsp.body, 'with plus')
483
484        req, handler = get_req('http://localhost:80/')
485        uri = webapp2.uri_for('escape', name='with/slash')
486        req, handler = get_req(uri)
487        rsp = req.get_response(app)
488        self.assertEqual(rsp.status_int, 200)
489        self.assertEqual(rsp.body, 'with/slash')
490
491    def test_handle_exception_with_error(self):
492        class HomeHandler(webapp2.RequestHandler):
493            def get(self, **kwargs):
494                raise TypeError()
495
496        def handle_exception(request, response, exception):
497            raise ValueError()
498
499        app = webapp2.WSGIApplication([
500            webapp2.Route('/', HomeHandler, name='home'),
501        ], debug=False)
502        app.error_handlers[500] = handle_exception
503
504        req = webapp2.Request.blank('/')
505        rsp = req.get_response(app)
506        self.assertEqual(rsp.status_int, 500)
507
508    def test_handle_exception_with_error_debug(self):
509        class HomeHandler(webapp2.RequestHandler):
510            def get(self, **kwargs):
511                raise TypeError()
512
513        def handle_exception(request, response, exception):
514            raise ValueError()
515
516        app = webapp2.WSGIApplication([
517            webapp2.Route('/', HomeHandler, name='home'),
518        ], debug=True)
519        app.error_handlers[500] = handle_exception
520
521        req = webapp2.Request.blank('/')
522        rsp = req.get_response(app)
523        self.assertEqual(rsp.status_int, 500)
524
525    def test_function_handler(self):
526        def my_view(request, *args, **kwargs):
527            return webapp2.Response('Hello, function world!')
528
529        def other_view(request, *args, **kwargs):
530            return webapp2.Response('Hello again, function world!')
531
532        '''
533        def one_more_view(request, response):
534            self.assertEqual(request.route_args, ())
535            self.assertEqual(request.route_kwargs, {'foo': 'bar'})
536            response.write('Hello you too, deprecated arguments world!')
537        '''
538        def one_more_view(request, *args, **kwargs):
539            self.assertEqual(args, ())
540            self.assertEqual(kwargs, {'foo': 'bar'})
541            return webapp2.Response('Hello you too!')
542
543        app = webapp2.WSGIApplication([
544            webapp2.Route('/', my_view),
545            webapp2.Route('/other', other_view),
546            webapp2.Route('/one-more/<foo>', one_more_view),
547            #webapp2.Route('/one-more/<foo>', one_more_view),
548        ])
549
550        req = webapp2.Request.blank('/')
551        rsp = req.get_response(app)
552        self.assertEqual(rsp.status_int, 200)
553        self.assertEqual(rsp.body, 'Hello, function world!')
554
555        # Twice to test factory.
556        req = webapp2.Request.blank('/')
557        rsp = req.get_response(app)
558        self.assertEqual(rsp.status_int, 200)
559        self.assertEqual(rsp.body, 'Hello, function world!')
560
561        req = webapp2.Request.blank('/other')
562        rsp = req.get_response(app)
563        self.assertEqual(rsp.status_int, 200)
564        self.assertEqual(rsp.body, 'Hello again, function world!')
565
566        # Twice to test factory.
567        req = webapp2.Request.blank('/other')
568        rsp = req.get_response(app)
569        self.assertEqual(rsp.status_int, 200)
570        self.assertEqual(rsp.body, 'Hello again, function world!')
571
572        req = webapp2.Request.blank('/one-more/bar')
573        rsp = req.get_response(app)
574        self.assertEqual(rsp.status_int, 200)
575        self.assertEqual(rsp.body, 'Hello you too!')
576
577    def test_custom_method(self):
578        class MyHandler(webapp2.RequestHandler):
579            def my_method(self):
580                self.response.out.write('Hello, custom method world!')
581
582            def my_other_method(self):
583                self.response.out.write('Hello again, custom method world!')
584
585        app = webapp2.WSGIApplication([
586            webapp2.Route('/', MyHandler, handler_method='my_method'),
587            webapp2.Route('/other', MyHandler, handler_method='my_other_method'),
588        ])
589
590        req = webapp2.Request.blank('/')
591        rsp = req.get_response(app)
592        self.assertEqual(rsp.status_int, 200)
593        self.assertEqual(rsp.body, 'Hello, custom method world!')
594
595        req = webapp2.Request.blank('/other')
596        rsp = req.get_response(app)
597        self.assertEqual(rsp.status_int, 200)
598        self.assertEqual(rsp.body, 'Hello again, custom method world!')
599
600    def test_custom_method_with_string(self):
601        app = webapp2.WSGIApplication([
602            webapp2.Route('/', handler='resources.handlers.CustomMethodHandler:custom_method'),
603            webapp2.Route('/bleh', handler='resources.handlers.CustomMethodHandler:custom_method'),
604        ])
605
606        req = webapp2.Request.blank('/')
607        rsp = req.get_response(app)
608        self.assertEqual(rsp.status_int, 200)
609        self.assertEqual(rsp.body, 'I am a custom method.')
610
611        req = webapp2.Request.blank('/bleh')
612        rsp = req.get_response(app)
613        self.assertEqual(rsp.status_int, 200)
614        self.assertEqual(rsp.body, 'I am a custom method.')
615
616        self.assertRaises(ValueError, webapp2.Route, '/', handler='resources.handlers.CustomMethodHandler:custom_method', handler_method='custom_method')
617
618    def test_factory_1(self):
619        app.debug = True
620        rsp = app.get_response('/bare')
621        self.assertEqual(rsp.status_int, 200)
622        self.assertEqual(rsp.body, 'I am not a RequestHandler but I work.')
623        app.debug = False
624
625    def test_factory_2(self):
626        """Very crazy stuff. Please ignore it."""
627        class MyHandler(object):
628            def __init__(self, request, response):
629                self.request = request
630                self.response = response
631
632            def __new__(cls, *args, **kwargs):
633                return cls.create_instance(*args, **kwargs)()
634
635            @classmethod
636            def create_instance(cls, *args, **kwargs):
637                obj = object.__new__(cls)
638                if isinstance(obj, cls):
639                    obj.__init__(*args, **kwargs)
640
641                return obj
642
643            def __call__(self):
644                return self
645
646            def dispatch(self):
647                self.response.write('hello')
648
649        app = webapp2.WSGIApplication([
650            webapp2.Route('/', handler=MyHandler),
651        ])
652
653        req = webapp2.Request.blank('/')
654        rsp = req.get_response(app)
655        self.assertEqual(rsp.status_int, 200)
656        self.assertEqual(rsp.body, 'hello')
657
658    def test_encoding(self):
659        class PostHandler(webapp2.RequestHandler):
660            def post(self):
661                foo = self.request.POST['foo']
662                if not foo:
663                    foo = 'empty'
664
665                self.response.write(foo)
666
667        app = webapp2.WSGIApplication([
668            webapp2.Route('/', PostHandler),
669        ], debug=True)
670
671        # foo with umlauts in the vowels.
672        value = 'f\xc3\xb6\xc3\xb6'
673
674        rsp = app.get_response('/', POST={'foo': value},
675            headers=[('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')])
676        self.assertEqual(rsp.body, 'föö')
677
678        rsp = app.get_response('/', POST={'foo': value},
679            headers=[('Content-Type', 'application/x-www-form-urlencoded')])
680        self.assertEqual(rsp.body, 'föö')
681
682
683if __name__ == '__main__':
684    test_base.main()
685