1"""test_utils"""
2import os, sys, time, unittest
3from nose.tools import eq_, assert_raises
4
5from routes.util import controller_scan, GenerationException
6from routes import *
7
8class TestUtils(unittest.TestCase):
9    def setUp(self):
10        m = Mapper(explicit=False)
11        m.minimization = True
12        m.connect('archive/:year/:month/:day', controller='blog', action='view', month=None, day=None,
13                  requirements={'month':'\d{1,2}','day':'\d{1,2}'})
14        m.connect('viewpost/:id', controller='post', action='view')
15        m.connect(':controller/:action/:id')
16        con = request_config()
17        con.mapper = m
18        con.host = 'www.test.com'
19        con.protocol = 'http'
20        if hasattr(con, 'environ'):
21            del con.environ
22        self.con = con
23
24    def test_url_for_with_nongen(self):
25        con = self.con
26        con.mapper_dict = {}
27
28        eq_('/blog', url_for('/blog'))
29        eq_('/blog?q=fred&q=here%20now', url_for('/blog', q=['fred', u'here now']))
30        eq_('/blog#here', url_for('/blog', anchor='here'))
31
32    def test_url_for_with_nongen_no_encoding(self):
33        con = self.con
34        con.mapper_dict = {}
35        con.mapper.encoding = None
36
37        eq_('/blog', url_for('/blog'))
38        eq_('/blog#here', url_for('/blog', anchor='here'))
39
40    def test_url_for_with_unicode(self):
41        con = self.con
42        con.mapper_dict = {}
43
44        eq_('/blog', url_for(controller='blog'))
45        eq_('/blog/view/umulat', url_for(controller='blog', action='view', id=u'umulat'))
46        eq_('/blog/view/umulat?other=%CE%B1%CF%83%CE%B4%CE%B3',
47            url_for(controller='blog', action='view', id=u'umulat', other=u'\u03b1\u03c3\u03b4\u03b3'))
48
49        url = URLGenerator(con.mapper, {})
50        for urlobj in [url_for, url]:
51            def raise_url():
52                return urlobj(u'/some/st\xc3rng')
53            assert_raises(Exception, raise_url)
54
55    def test_url_for(self):
56        con = self.con
57        con.mapper_dict = {}
58        url = URLGenerator(con.mapper, {'HTTP_HOST':'www.test.com:80'})
59
60        for urlobj in [url_for, url]:
61            eq_('/blog', urlobj(controller='blog'))
62            eq_('/content', urlobj())
63            eq_('https://www.test.com/viewpost', urlobj(controller='post', action='view', protocol='https'))
64            eq_('http://www.test.org/content', urlobj(host='www.test.org'))
65            eq_('//www.test.com/viewpost', urlobj(controller='post', action='view', protocol=''))
66            eq_('//www.test.org/content', urlobj(host='www.test.org', protocol=''))
67
68    def test_url_raises(self):
69        con = self.con
70        con.mapper.explicit = True
71        con.mapper_dict = {}
72        url = URLGenerator(con.mapper, {})
73        assert_raises(GenerationException, url_for, action='juice')
74        assert_raises(GenerationException, url, action='juice')
75
76    def test_url_for_with_defaults(self):
77        con = self.con
78        con.mapper_dict = {'controller':'blog','action':'view','id':4}
79        url = URLGenerator(con.mapper, {'wsgiorg.routing_args':((), con.mapper_dict)})
80
81        eq_('/blog/view/4', url_for())
82        eq_('/post/index/4', url_for(controller='post'))
83        eq_('/blog/view/2', url_for(id=2))
84        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
85
86        eq_('/blog/view/4', url.current())
87        eq_('/post/index/4', url.current(controller='post'))
88        eq_('/blog/view/2', url.current(id=2))
89        eq_('/viewpost/4', url.current(controller='post', action='view', id=4))
90
91        con.mapper_dict = {'controller':'blog','action':'view','year':2004}
92        url = URLGenerator(con.mapper, {'wsgiorg.routing_args':((), con.mapper_dict)})
93
94        eq_('/archive/2004/10', url_for(month=10))
95        eq_('/archive/2004/9/2', url_for(month=9, day=2))
96        eq_('/blog', url_for(controller='blog', year=None))
97
98        eq_('/archive/2004/10', url.current(month=10))
99        eq_('/archive/2004/9/2', url.current(month=9, day=2))
100        eq_('/blog', url.current(controller='blog', year=None))
101
102    def test_url_for_with_more_defaults(self):
103        con = self.con
104        con.mapper_dict = {'controller':'blog','action':'view','id':4}
105        url = URLGenerator(con.mapper, {'wsgiorg.routing_args':((), con.mapper_dict)})
106
107        eq_('/blog/view/4', url_for())
108        eq_('/post/index/4', url_for(controller='post'))
109        eq_('/blog/view/2', url_for(id=2))
110        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
111
112        eq_('/blog/view/4', url.current())
113        eq_('/post/index/4', url.current(controller='post'))
114        eq_('/blog/view/2', url.current(id=2))
115        eq_('/viewpost/4', url.current(controller='post', action='view', id=4))
116
117        con.mapper_dict = {'controller':'blog','action':'view','year':2004}
118        url = URLGenerator(con.mapper, {'wsgiorg.routing_args':((), con.mapper_dict)})
119        eq_('/archive/2004/10', url_for(month=10))
120        eq_('/archive/2004/9/2', url_for(month=9, day=2))
121        eq_('/blog', url_for(controller='blog', year=None))
122        eq_('/archive/2004', url_for())
123
124        eq_('/archive/2004/10', url.current(month=10))
125        eq_('/archive/2004/9/2', url.current(month=9, day=2))
126        eq_('/blog', url.current(controller='blog', year=None))
127        eq_('/archive/2004', url.current())
128
129    def test_url_for_with_defaults_and_qualified(self):
130        m = self.con.mapper
131        m.connect('home', '', controller='blog', action='splash')
132        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
133        m.connect(':controller/:action/:id')
134        m.create_regs(['content','blog','admin/comments'])
135        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='www.example.com', PATH_INFO='/blog/view/4')
136        self.con.environ.update({'wsgiorg.routing_args':((), self.con.mapper_dict)})
137        url = URLGenerator(m, self.con.environ)
138
139        eq_('/blog/view/4', url_for())
140        eq_('/post/index/4', url_for(controller='post'))
141        eq_('http://www.example.com/blog/view/4', url_for(qualified=True))
142        eq_('/blog/view/2', url_for(id=2))
143        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
144
145        eq_('/blog/view/4', url.current())
146        eq_('/post/index/4', url.current(controller='post'))
147        eq_('http://www.example.com/blog/view/4', url.current(qualified=True))
148        eq_('/blog/view/2', url.current(id=2))
149        eq_('/viewpost/4', url.current(controller='post', action='view', id=4))
150
151        env = dict(SCRIPT_NAME='', SERVER_NAME='www.example.com', SERVER_PORT='8080', PATH_INFO='/blog/view/4')
152        env['wsgi.url_scheme'] = 'http'
153        self.con.environ = env
154        self.con.environ.update({'wsgiorg.routing_args':((), self.con.mapper_dict)})
155        url = URLGenerator(m, self.con.environ)
156
157        eq_('/post/index/4', url_for(controller='post'))
158        eq_('http://www.example.com:8080/blog/view/4', url_for(qualified=True))
159
160        eq_('/post/index/4', url.current(controller='post'))
161        eq_('http://www.example.com:8080/blog/view/4', url.current(qualified=True))
162
163    def test_route_overflow(self):
164        m = self.con.mapper
165        m.create_regs(["x"*50000])
166        m.connect('route-overflow', "x"*50000)
167        url = URLGenerator(m, {})
168        eq_("/%s" % ("x"*50000), url('route-overflow'))
169
170    def test_with_route_names(self):
171        m = self.con.mapper
172        self.con.mapper_dict = {}
173        m.connect('home', '', controller='blog', action='splash')
174        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
175        m.create_regs(['content','blog','admin/comments'])
176        url = URLGenerator(m, {})
177
178        for urlobj in [url, url_for]:
179            eq_('/content/view', urlobj(controller='content', action='view'))
180            eq_('/content', urlobj(controller='content'))
181            eq_('/admin/comments', urlobj(controller='admin/comments'))
182            eq_('/category', urlobj('category_home'))
183            eq_('/category/food', urlobj('category_home', section='food'))
184            eq_('/', urlobj('home'))
185
186    def test_with_route_names_and_defaults(self):
187        m = self.con.mapper
188        self.con.mapper_dict = {}
189        m.connect('home', '', controller='blog', action='splash')
190        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
191        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
192        m.create_regs(['content','blog','admin/comments','building'])
193
194        self.con.mapper_dict = dict(controller='building', action='showjacks', campus='wilma', building='port')
195        url = URLGenerator(m, {'wsgiorg.routing_args':((), self.con.mapper_dict)})
196
197        eq_('/building/wilma/port/alljacks', url_for())
198        eq_('/', url_for('home'))
199        eq_('/building/wilma/port/alljacks', url.current())
200        eq_('/', url.current('home'))
201
202    def test_with_route_names_and_hardcode(self):
203        m = self.con.mapper
204        self.con.mapper_dict = {}
205        m.hardcode_names = False
206
207        m.connect('home', '', controller='blog', action='splash')
208        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
209        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
210        m.connect('gallery_thumb', 'gallery/:(img_id)_thumbnail.jpg')
211        m.connect('gallery', 'gallery/:(img_id).jpg')
212        m.create_regs(['content','blog','admin/comments','building'])
213
214        self.con.mapper_dict = dict(controller='building', action='showjacks', campus='wilma', building='port')
215        url = URLGenerator(m, {'wsgiorg.routing_args':((), self.con.mapper_dict)})
216        eq_('/building/wilma/port/alljacks', url_for())
217        eq_('/', url_for('home'))
218        eq_('/gallery/home_thumbnail.jpg', url_for('gallery_thumb', img_id='home'))
219        eq_('/gallery/home_thumbnail.jpg', url_for('gallery', img_id='home'))
220
221        eq_('/building/wilma/port/alljacks', url.current())
222        eq_('/', url.current('home'))
223        eq_('/gallery/home_thumbnail.jpg', url.current('gallery_thumb', img_id='home'))
224        eq_('/gallery/home_thumbnail.jpg', url.current('gallery', img_id='home'))
225
226        m.hardcode_names = True
227        eq_('/gallery/home_thumbnail.jpg', url_for('gallery_thumb', img_id='home'))
228        eq_('/gallery/home.jpg', url_for('gallery', img_id='home'))
229
230        eq_('/gallery/home_thumbnail.jpg', url.current('gallery_thumb', img_id='home'))
231        eq_('/gallery/home.jpg', url.current('gallery', img_id='home'))
232        m.hardcode_names = False
233
234    def test_redirect_to(self):
235        m = self.con.mapper
236        self.con.mapper_dict = {}
237        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='www.example.com')
238        result = None
239        def printer(echo):
240            redirect_to.result = echo
241        self.con.redirect = printer
242        m.create_regs(['content','blog','admin/comments'])
243
244        redirect_to(controller='content', action='view')
245        eq_('/content/view', redirect_to.result)
246        redirect_to(controller='content', action='lookup', id=4)
247        eq_('/content/lookup/4', redirect_to.result)
248        redirect_to(controller='admin/comments',action='splash')
249        eq_('/admin/comments/splash', redirect_to.result)
250        redirect_to('http://www.example.com/')
251        eq_('http://www.example.com/', redirect_to.result)
252        redirect_to('/somewhere.html', var='keyword')
253        eq_('/somewhere.html?var=keyword', redirect_to.result)
254
255    def test_redirect_to_with_route_names(self):
256        m = self.con.mapper
257        self.con.mapper_dict = {}
258        result = None
259        def printer(echo):
260            redirect_to.result = echo
261        self.con.redirect = printer
262        m.connect('home', '', controller='blog', action='splash')
263        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
264        m.create_regs(['content','blog','admin/comments'])
265
266        redirect_to(controller='content', action='view')
267        eq_('/content/view', redirect_to.result)
268        redirect_to(controller='content')
269        eq_('/content', redirect_to.result)
270        redirect_to(controller='admin/comments')
271        eq_('/admin/comments', redirect_to.result)
272        redirect_to('category_home')
273        eq_('/category', redirect_to.result)
274        redirect_to('category_home', section='food')
275        eq_('/category/food', redirect_to.result)
276        redirect_to('home')
277        eq_('/', redirect_to.result)
278
279    def test_static_route(self):
280        m = self.con.mapper
281        self.con.mapper_dict = {}
282        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='example.com')
283        m.connect(':controller/:action/:id')
284        m.connect('home', 'http://www.groovie.org/', _static=True)
285        m.connect('space', '/nasa/images', _static=True)
286        m.create_regs(['content', 'blog'])
287
288        url = URLGenerator(m, {})
289        for urlobj in [url_for, url]:
290            eq_('http://www.groovie.org/', urlobj('home'))
291            eq_('http://www.groovie.org/?s=stars', urlobj('home', s='stars'))
292            eq_('/content/view', urlobj(controller='content', action='view'))
293            eq_('/nasa/images?search=all', urlobj('space', search='all'))
294
295    def test_static_route_with_script(self):
296        m = self.con.mapper
297        self.con.mapper_dict = {}
298        self.con.environ = dict(SCRIPT_NAME='/webapp', HTTP_HOST='example.com')
299        m.connect(':controller/:action/:id')
300        m.connect('home', 'http://www.groovie.org/', _static=True)
301        m.connect('space', '/nasa/images', _static=True)
302        m.connect('login', '/login', action='nowhereville')
303        m.create_regs(['content', 'blog'])
304
305        self.con.environ.update({'wsgiorg.routing_args':((), {})})
306        url = URLGenerator(m, self.con.environ)
307        for urlobj in [url_for, url]:
308            eq_('http://www.groovie.org/', urlobj('home'))
309            eq_('http://www.groovie.org/?s=stars', urlobj('home', s='stars'))
310            eq_('/webapp/content/view', urlobj(controller='content', action='view'))
311            eq_('/webapp/nasa/images?search=all', urlobj('space', search='all'))
312            eq_('http://example.com/webapp/nasa/images', urlobj('space', protocol='http'))
313            eq_('http://example.com/webapp/login', urlobj('login', qualified=True))
314
315    def test_static_route_with_vars(self):
316        m = self.con.mapper
317        self.con.mapper_dict = {}
318        self.con.environ = dict(SCRIPT_NAME='/webapp', HTTP_HOST='example.com')
319        m.connect('home', 'http://{domain}.groovie.org/{location}', _static=True)
320        m.connect('space', '/nasa/{location}', _static=True)
321        m.create_regs(['home', 'space'])
322
323        self.con.environ.update({'wsgiorg.routing_args':((), {})})
324        url = URLGenerator(m, self.con.environ)
325        for urlobj in [url_for, url]:
326            assert_raises(GenerationException, urlobj, 'home')
327            assert_raises(GenerationException, urlobj, 'home', domain='fred')
328            assert_raises(GenerationException, urlobj, 'home', location='index')
329            eq_('http://fred.groovie.org/index', urlobj('home', domain='fred', location='index'))
330            eq_('http://fred.groovie.org/index?search=all', urlobj('home', domain='fred', location='index', search='all'))
331            eq_('/webapp/nasa/images?search=all', urlobj('space', location='images', search='all'))
332            eq_('http://example.com/webapp/nasa/images', urlobj('space', location='images', protocol='http'))
333
334    def test_static_route_with_vars_and_defaults(self):
335        m = self.con.mapper
336        self.con.mapper_dict = {}
337        self.con.environ = dict(SCRIPT_NAME='/webapp', HTTP_HOST='example.com')
338        m.connect('home', 'http://{domain}.groovie.org/{location}', domain='routes', _static=True)
339        m.connect('space', '/nasa/{location}', location='images', _static=True)
340        m.create_regs(['home', 'space'])
341
342        self.con.environ.update({'wsgiorg.routing_args':((), {})})
343        url = URLGenerator(m, self.con.environ)
344
345        assert_raises(GenerationException, url_for, 'home')
346        assert_raises(GenerationException, url_for, 'home', domain='fred')
347        eq_('http://routes.groovie.org/index', url_for('home', location='index'))
348        eq_('http://fred.groovie.org/index', url_for('home', domain='fred', location='index'))
349        eq_('http://routes.groovie.org/index?search=all', url_for('home', location='index', search='all'))
350        eq_('http://fred.groovie.org/index?search=all', url_for('home', domain='fred', location='index', search='all'))
351        eq_('/webapp/nasa/articles?search=all', url_for('space', location='articles', search='all'))
352        eq_('http://example.com/webapp/nasa/articles', url_for('space', location='articles', protocol='http'))
353        eq_('/webapp/nasa/images?search=all', url_for('space', search='all'))
354        eq_('http://example.com/webapp/nasa/images', url_for('space', protocol='http'))
355
356        assert_raises(GenerationException, url.current, 'home')
357        assert_raises(GenerationException, url.current, 'home', domain='fred')
358        eq_('http://routes.groovie.org/index', url.current('home', location='index'))
359        eq_('http://fred.groovie.org/index', url.current('home', domain='fred', location='index'))
360        eq_('http://routes.groovie.org/index?search=all', url.current('home', location='index', search='all'))
361        eq_('http://fred.groovie.org/index?search=all', url.current('home', domain='fred', location='index', search='all'))
362        eq_('/webapp/nasa/articles?search=all', url.current('space', location='articles', search='all'))
363        eq_('http://example.com/webapp/nasa/articles', url.current('space', location='articles', protocol='http'))
364        eq_('/webapp/nasa/images?search=all', url.current('space', search='all'))
365        eq_('http://example.com/webapp/nasa/images', url.current('space', protocol='http'))
366
367
368    def test_static_route_with_vars_and_requirements(self):
369        m = self.con.mapper
370        self.con.mapper_dict = {}
371        self.con.environ = dict(SCRIPT_NAME='/webapp', HTTP_HOST='example.com')
372        m.connect('home', 'http://{domain}.groovie.org/{location}', requirements=dict(domain='fred|bob'), _static=True)
373        m.connect('space', '/nasa/articles/{year}/{month}', requirements=dict(year=r'\d{2,4}', month=r'\d{1,2}'), _static=True)
374        m.create_regs(['home', 'space'])
375
376
377        self.con.environ.update({'wsgiorg.routing_args':((), {})})
378        url = URLGenerator(m, self.con.environ)
379
380        assert_raises(GenerationException, url_for, 'home', domain='george', location='index')
381        assert_raises(GenerationException, url_for, 'space', year='asdf', month='1')
382        assert_raises(GenerationException, url_for, 'space', year='2004', month='a')
383        assert_raises(GenerationException, url_for, 'space', year='1', month='1')
384        assert_raises(GenerationException, url_for, 'space', year='20045', month='1')
385        assert_raises(GenerationException, url_for, 'space', year='2004', month='123')
386        eq_('http://fred.groovie.org/index', url_for('home', domain='fred', location='index'))
387        eq_('http://bob.groovie.org/index', url_for('home', domain='bob', location='index'))
388        eq_('http://fred.groovie.org/asdf', url_for('home', domain='fred', location='asdf'))
389        eq_('/webapp/nasa/articles/2004/6', url_for('space', year='2004', month='6'))
390        eq_('/webapp/nasa/articles/2004/12', url_for('space', year='2004', month='12'))
391        eq_('/webapp/nasa/articles/89/6', url_for('space', year='89', month='6'))
392
393        assert_raises(GenerationException, url.current, 'home', domain='george', location='index')
394        assert_raises(GenerationException, url.current, 'space', year='asdf', month='1')
395        assert_raises(GenerationException, url.current, 'space', year='2004', month='a')
396        assert_raises(GenerationException, url.current, 'space', year='1', month='1')
397        assert_raises(GenerationException, url.current, 'space', year='20045', month='1')
398        assert_raises(GenerationException, url.current, 'space', year='2004', month='123')
399        eq_('http://fred.groovie.org/index', url.current('home', domain='fred', location='index'))
400        eq_('http://bob.groovie.org/index', url.current('home', domain='bob', location='index'))
401        eq_('http://fred.groovie.org/asdf', url.current('home', domain='fred', location='asdf'))
402        eq_('/webapp/nasa/articles/2004/6', url.current('space', year='2004', month='6'))
403        eq_('/webapp/nasa/articles/2004/12', url.current('space', year='2004', month='12'))
404        eq_('/webapp/nasa/articles/89/6', url.current('space', year='89', month='6'))
405
406    def test_no_named_path(self):
407        m = self.con.mapper
408        self.con.mapper_dict = {}
409        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='example.com')
410        m.connect(':controller/:action/:id')
411        m.connect('home', 'http://www.groovie.org/', _static=True)
412        m.connect('space', '/nasa/images', _static=True)
413        m.create_regs(['content', 'blog'])
414
415        url = URLGenerator(m, {})
416        for urlobj in [url_for, url]:
417            eq_('http://www.google.com/search', urlobj('http://www.google.com/search'))
418            eq_('http://www.google.com/search?q=routes', urlobj('http://www.google.com/search', q='routes'))
419            eq_('/delicious.jpg', urlobj('/delicious.jpg'))
420            eq_('/delicious/search?v=routes', urlobj('/delicious/search', v='routes'))
421
422    def test_append_slash(self):
423        m = self.con.mapper
424        self.con.mapper_dict = {}
425        m.append_slash = True
426        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='example.com')
427        m.connect(':controller/:action/:id')
428        m.connect('home', 'http://www.groovie.org/', _static=True)
429        m.connect('space', '/nasa/images', _static=True)
430        m.create_regs(['content', 'blog'])
431
432        url = URLGenerator(m, {})
433        for urlobj in [url_for, url]:
434            eq_('http://www.google.com/search', urlobj('http://www.google.com/search'))
435            eq_('http://www.google.com/search?q=routes', urlobj('http://www.google.com/search', q='routes'))
436            eq_('/delicious.jpg', urlobj('/delicious.jpg'))
437            eq_('/delicious/search?v=routes', urlobj('/delicious/search', v='routes'))
438            eq_('/content/list/', urlobj(controller='/content', action='list'))
439            eq_('/content/list/?page=1', urlobj(controller='/content', action='list', page='1'))
440
441    def test_no_named_path_with_script(self):
442        m = self.con.mapper
443        self.con.mapper_dict = {}
444        self.con.environ = dict(SCRIPT_NAME='/webapp', HTTP_HOST='example.com')
445        m.connect(':controller/:action/:id')
446        m.connect('home', 'http://www.groovie.org/', _static=True)
447        m.connect('space', '/nasa/images', _static=True)
448        m.create_regs(['content', 'blog'])
449
450        url = URLGenerator(m, self.con.environ)
451        for urlobj in [url_for, url]:
452            eq_('http://www.google.com/search', urlobj('http://www.google.com/search'))
453            eq_('http://www.google.com/search?q=routes', urlobj('http://www.google.com/search', q='routes'))
454            eq_('/webapp/delicious.jpg', urlobj('/delicious.jpg'))
455            eq_('/webapp/delicious/search?v=routes', urlobj('/delicious/search', v='routes'))
456
457    def test_route_filter(self):
458        def article_filter(kargs):
459            article = kargs.pop('article', None)
460            if article is not None:
461                kargs.update(
462                    dict(year=article.get('year', 2004),
463                         month=article.get('month', 12),
464                         day=article.get('day', 20),
465                         slug=article.get('slug', 'default')
466                    )
467                )
468            return kargs
469
470        self.con.mapper_dict = {}
471        self.con.environ = dict(SCRIPT_NAME='', HTTP_HOST='example.com')
472
473        m = Mapper(explicit=False)
474        m.minimization = True
475        m.connect(':controller/:(action)-:(id).html')
476        m.connect('archives', 'archives/:year/:month/:day/:slug', controller='archives', action='view',
477                  _filter=article_filter)
478        m.create_regs(['content','archives','admin/comments'])
479        self.con.mapper = m
480
481        url = URLGenerator(m, self.con.environ)
482        for urlobj in [url_for, url]:
483            assert_raises(Exception, urlobj, controller='content', action='view')
484            assert_raises(Exception, urlobj, controller='content')
485
486            eq_('/content/view-3.html', urlobj(controller='content', action='view', id=3))
487            eq_('/content/index-2.html', urlobj(controller='content', id=2))
488
489            eq_('/archives/2005/10/5/happy',
490                urlobj('archives',year=2005, month=10, day=5, slug='happy'))
491            story = dict(year=2003, month=8, day=2, slug='woopee')
492            empty = {}
493            eq_({'controller':'archives','action':'view','year':'2005',
494                'month':'10','day':'5','slug':'happy'}, m.match('/archives/2005/10/5/happy'))
495            eq_('/archives/2003/8/2/woopee', urlobj('archives', article=story))
496            eq_('/archives/2004/12/20/default', urlobj('archives', article=empty))
497
498    def test_with_ssl_environ(self):
499        base_environ = dict(SCRIPT_NAME='', HTTPS='on', SERVER_PORT='443', PATH_INFO='/',
500            HTTP_HOST='example.com', SERVER_NAME='example.com')
501        self.con.mapper_dict = {}
502        self.con.environ = base_environ.copy()
503
504        m = Mapper(explicit=False)
505        m.minimization = True
506        m.connect(':controller/:action/:id')
507        m.create_regs(['content','archives','admin/comments'])
508        m.sub_domains = True
509        self.con.mapper = m
510
511        url = URLGenerator(m, self.con.environ)
512        for urlobj in [url_for, url]:
513
514            # HTTPS is on, but we're running on a different port internally
515            eq_(self.con.protocol, 'https')
516            eq_('/content/view', urlobj(controller='content', action='view'))
517            eq_('/content/index/2', urlobj(controller='content', id=2))
518            eq_('https://nowhere.com/content', urlobj(host='nowhere.com', controller='content'))
519
520            # If HTTPS is on, but the port isn't 443, we'll need to include the port info
521            environ = base_environ.copy()
522            environ.update(dict(SERVER_PORT='8080'))
523            self.con.environ = environ
524            self.con.mapper_dict = {}
525            eq_('/content/index/2', urlobj(controller='content', id=2))
526            eq_('https://nowhere.com/content', urlobj(host='nowhere.com', controller='content'))
527            eq_('https://nowhere.com:8080/content', urlobj(host='nowhere.com:8080', controller='content'))
528            eq_('http://nowhere.com/content', urlobj(host='nowhere.com', protocol='http', controller='content'))
529            eq_('http://home.com/content', urlobj(host='home.com', protocol='http', controller='content'))
530
531
532    def test_with_http_environ(self):
533        base_environ = dict(SCRIPT_NAME='', SERVER_PORT='1080', PATH_INFO='/',
534            HTTP_HOST='example.com', SERVER_NAME='example.com')
535        base_environ['wsgi.url_scheme'] = 'http'
536        self.con.environ = base_environ.copy()
537        self.con.mapper_dict = {}
538
539        m = Mapper(explicit=False)
540        m.minimization = True
541        m.connect(':controller/:action/:id')
542        m.create_regs(['content','archives','admin/comments'])
543        self.con.mapper = m
544
545        url = URLGenerator(m, self.con.environ)
546        for urlobj in [url_for, url]:
547            eq_(self.con.protocol, 'http')
548            eq_('/content/view', urlobj(controller='content', action='view'))
549            eq_('/content/index/2', urlobj(controller='content', id=2))
550            eq_('https://example.com/content', urlobj(protocol='https', controller='content'))
551
552
553    def test_subdomains(self):
554        base_environ = dict(SCRIPT_NAME='', PATH_INFO='/', HTTP_HOST='example.com', SERVER_NAME='example.com')
555        self.con.mapper_dict = {}
556        self.con.environ = base_environ.copy()
557
558        m = Mapper(explicit=False)
559        m.minimization = True
560        m.sub_domains = True
561        m.connect(':controller/:action/:id')
562        m.create_regs(['content','archives','admin/comments'])
563        self.con.mapper = m
564
565        url = URLGenerator(m, self.con.environ)
566        for urlobj in [url_for, url]:
567            eq_('/content/view', urlobj(controller='content', action='view'))
568            eq_('/content/index/2', urlobj(controller='content', id=2))
569            environ = base_environ.copy()
570            environ.update(dict(HTTP_HOST='sub.example.com'))
571            self.con.environ = environ
572            self.con.mapper_dict = {'sub_domain':'sub'}
573            eq_('/content/view/3', urlobj(controller='content', action='view', id=3))
574            eq_('http://new.example.com/content', urlobj(controller='content', sub_domain='new'))
575
576    def test_subdomains_with_exceptions(self):
577        base_environ = dict(SCRIPT_NAME='', PATH_INFO='/', HTTP_HOST='example.com', SERVER_NAME='example.com')
578        self.con.mapper_dict = {}
579        self.con.environ = base_environ.copy()
580
581        m = Mapper(explicit=False)
582        m.minimization = True
583        m.sub_domains = True
584        m.sub_domains_ignore = ['www']
585        m.connect(':controller/:action/:id')
586        m.create_regs(['content','archives','admin/comments'])
587        self.con.mapper = m
588
589        url = URLGenerator(m, self.con.environ)
590        eq_('/content/view', url_for(controller='content', action='view'))
591        eq_('/content/index/2', url_for(controller='content', id=2))
592        eq_('/content/view', url(controller='content', action='view'))
593        eq_('/content/index/2', url(controller='content', id=2))
594
595        environ = base_environ.copy()
596        environ.update(dict(HTTP_HOST='sub.example.com'))
597        self.con.environ = environ
598        self.con.mapper_dict = {'sub_domain':'sub'}
599        self.con.environ.update({'wsgiorg.routing_args':((), self.con.mapper_dict)})
600        url = URLGenerator(m, self.con.environ)
601
602        eq_('/content/view/3', url_for(controller='content', action='view', id=3))
603        eq_('http://new.example.com/content', url_for(controller='content', sub_domain='new'))
604        eq_('http://example.com/content', url_for(controller='content', sub_domain='www'))
605        eq_('/content/view/3', url(controller='content', action='view', id=3))
606        eq_('http://new.example.com/content', url(controller='content', sub_domain='new'))
607        eq_('http://example.com/content', url(controller='content', sub_domain='www'))
608
609        self.con.mapper_dict = {'sub_domain':'www'}
610        self.con.environ.update({'wsgiorg.routing_args':((), self.con.mapper_dict)})
611        url = URLGenerator(m, self.con.environ)
612
613        eq_('http://example.com/content/view/3', url_for(controller='content', action='view', id=3))
614        eq_('http://new.example.com/content', url_for(controller='content', sub_domain='new'))
615        eq_('/content', url_for(controller='content', sub_domain='sub'))
616
617        # This requires the sub-domain, because we don't automatically go to the existing match dict
618        eq_('http://example.com/content/view/3', url(controller='content', action='view', id=3, sub_domain='www'))
619        eq_('http://new.example.com/content', url(controller='content', sub_domain='new'))
620        eq_('/content', url(controller='content', sub_domain='sub'))
621
622    def test_subdomains_with_named_routes(self):
623        base_environ = dict(SCRIPT_NAME='', PATH_INFO='/', HTTP_HOST='example.com', SERVER_NAME='example.com')
624        self.con.mapper_dict = {}
625        self.con.environ = base_environ.copy()
626
627        m = Mapper(explicit=False)
628        m.minimization = True
629        m.sub_domains = True
630        m.connect(':controller/:action/:id')
631        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
632        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
633        m.create_regs(['content','blog','admin/comments','building'])
634        self.con.mapper = m
635
636        url = URLGenerator(m, self.con.environ)
637        for urlobj in [url_for, url]:
638            eq_('/content/view', urlobj(controller='content', action='view'))
639            eq_('/content/index/2', urlobj(controller='content', id=2))
640            eq_('/category', urlobj('category_home'))
641            eq_('http://new.example.com/category', urlobj('category_home', sub_domain='new'))
642
643        environ = base_environ.copy()
644        environ.update(dict(HTTP_HOST='sub.example.com'))
645        self.con.environ = environ
646        self.con.mapper_dict = {'sub_domain':'sub'}
647        self.con.environ.update({'wsgiorg.routing_args':((), self.con.mapper_dict)})
648        url = URLGenerator(m, self.con.environ)
649
650        eq_('/content/view/3', url_for(controller='content', action='view', id=3))
651        eq_('http://joy.example.com/building/west/merlot/alljacks',
652            url_for('building', campus='west', building='merlot', sub_domain='joy'))
653        eq_('http://example.com/category/feeds', url_for('category_home', section='feeds', sub_domain=None))
654
655        eq_('/content/view/3', url(controller='content', action='view', id=3))
656        eq_('http://joy.example.com/building/west/merlot/alljacks',
657            url('building', campus='west', building='merlot', sub_domain='joy'))
658        eq_('http://example.com/category/feeds', url('category_home', section='feeds', sub_domain=None))
659
660
661    def test_subdomains_with_ports(self):
662        base_environ = dict(SCRIPT_NAME='', PATH_INFO='/', HTTP_HOST='example.com:8000', SERVER_NAME='example.com')
663        self.con.mapper_dict = {}
664        self.con.environ = base_environ.copy()
665
666        m = Mapper(explicit=False)
667        m.minimization = True
668        m.sub_domains = True
669        m.connect(':controller/:action/:id')
670        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
671        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
672        m.create_regs(['content','blog','admin/comments','building'])
673        self.con.mapper = m
674
675        url = URLGenerator(m, self.con.environ)
676        for urlobj in [url, url_for]:
677            self.con.environ['HTTP_HOST'] = 'example.com:8000'
678            eq_('/content/view', urlobj(controller='content', action='view'))
679            eq_('/category', urlobj('category_home'))
680            eq_('http://new.example.com:8000/category', urlobj('category_home', sub_domain='new'))
681            eq_('http://joy.example.com:8000/building/west/merlot/alljacks',
682                urlobj('building', campus='west', building='merlot', sub_domain='joy'))
683
684            self.con.environ['HTTP_HOST'] = 'example.com'
685            del self.con.environ['routes.cached_hostinfo']
686            eq_('http://new.example.com/category', urlobj('category_home', sub_domain='new'))
687
688    def test_subdomains_with_default(self):
689        base_environ = dict(SCRIPT_NAME='', PATH_INFO='/', HTTP_HOST='example.com:8000', SERVER_NAME='example.com')
690        self.con.mapper_dict = {}
691        self.con.environ = base_environ.copy()
692
693        m = Mapper(explicit=False)
694        m.minimization = True
695        m.sub_domains = True
696        m.connect(':controller/:action/:id')
697        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home',
698                  sub_domain='cat', conditions=dict(sub_domain=['cat']))
699        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
700        m.create_regs(['content','blog','admin/comments','building'])
701        self.con.mapper = m
702
703        urlobj = URLGenerator(m, self.con.environ)
704        self.con.environ['HTTP_HOST'] = 'example.com:8000'
705        eq_('/content/view', urlobj(controller='content', action='view'))
706        eq_('http://cat.example.com:8000/category', urlobj('category_home'))
707
708        self.con.environ['HTTP_HOST'] = 'example.com'
709        del self.con.environ['routes.cached_hostinfo']
710
711        assert_raises(GenerationException, lambda: urlobj('category_home', sub_domain='new'))
712
713
714    def test_controller_scan(self):
715        here_dir = os.path.dirname(__file__)
716        controller_dir = os.path.join(os.path.dirname(here_dir),
717            os.path.join('test_files', 'controller_files'))
718        controllers = controller_scan(controller_dir)
719        eq_(len(controllers), 3)
720        eq_(controllers[0], 'admin/users')
721        eq_(controllers[1], 'content')
722        eq_(controllers[2], 'users')
723
724    def test_auto_controller_scan(self):
725        here_dir = os.path.dirname(__file__)
726        controller_dir = os.path.join(os.path.dirname(here_dir),
727            os.path.join('test_files', 'controller_files'))
728        m = Mapper(directory=controller_dir, explicit=False)
729        m.minimization = True
730        m.always_scan = True
731        m.connect(':controller/:action/:id')
732
733        eq_({'action':'index', 'controller':'content','id':None}, m.match('/content'))
734        eq_({'action':'index', 'controller':'users','id':None}, m.match('/users'))
735        eq_({'action':'index', 'controller':'admin/users','id':None}, m.match('/admin/users'))
736
737class TestUtilsWithExplicit(unittest.TestCase):
738    def setUp(self):
739        m = Mapper(explicit=True)
740        m.minimization = True
741        m.connect('archive/:year/:month/:day', controller='blog', action='view', month=None, day=None,
742                  requirements={'month':'\d{1,2}','day':'\d{1,2}'})
743        m.connect('viewpost/:id', controller='post', action='view', id=None)
744        m.connect(':controller/:action/:id')
745        con = request_config()
746        con.mapper = m
747        con.host = 'www.test.com'
748        con.protocol = 'http'
749        self.con = con
750
751    def test_url_for(self):
752        con = self.con
753        con.mapper_dict = {}
754
755        assert_raises(Exception, url_for, controller='blog')
756        assert_raises(Exception, url_for)
757        eq_('/blog/view/3', url_for(controller='blog', action='view', id=3))
758        eq_('https://www.test.com/viewpost', url_for(controller='post', action='view', protocol='https'))
759        eq_('http://www.test.org/content/view/2', url_for(host='www.test.org', controller='content', action='view', id=2))
760
761    def test_url_for_with_defaults(self):
762        con = self.con
763        con.mapper_dict = {'controller':'blog','action':'view','id':4}
764
765        assert_raises(Exception, url_for)
766        assert_raises(Exception, url_for, controller='post')
767        assert_raises(Exception, url_for, id=2)
768        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
769
770        con.mapper_dict = {'controller':'blog','action':'view','year':2004}
771        assert_raises(Exception, url_for, month=10)
772        assert_raises(Exception, url_for, month=9, day=2)
773        assert_raises(Exception, url_for, controller='blog', year=None)
774
775    def test_url_for_with_more_defaults(self):
776        con = self.con
777        con.mapper_dict = {'controller':'blog','action':'view','id':4}
778
779        assert_raises(Exception, url_for)
780        assert_raises(Exception, url_for, controller='post')
781        assert_raises(Exception, url_for, id=2)
782        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
783
784        con.mapper_dict = {'controller':'blog','action':'view','year':2004}
785        assert_raises(Exception, url_for, month=10)
786        assert_raises(Exception, url_for)
787
788    def test_url_for_with_defaults_and_qualified(self):
789        m = self.con.mapper
790        m.connect('home', '', controller='blog', action='splash')
791        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
792        m.connect(':controller/:action/:id')
793        m.create_regs(['content','blog','admin/comments'])
794        env = dict(SCRIPT_NAME='', SERVER_NAME='www.example.com', SERVER_PORT='80', PATH_INFO='/blog/view/4')
795        env['wsgi.url_scheme'] = 'http'
796
797        self.con.environ = env
798
799        assert_raises(Exception, url_for)
800        assert_raises(Exception, url_for, controller='post')
801        assert_raises(Exception, url_for, id=2)
802        assert_raises(Exception, url_for, qualified=True, controller='blog', id=4)
803        eq_('http://www.example.com/blog/view/4', url_for(qualified=True, controller='blog', action='view', id=4))
804        eq_('/viewpost/4', url_for(controller='post', action='view', id=4))
805
806        env = dict(SCRIPT_NAME='', SERVER_NAME='www.example.com', SERVER_PORT='8080', PATH_INFO='/blog/view/4')
807        env['wsgi.url_scheme'] = 'http'
808        self.con.environ = env
809        assert_raises(Exception, url_for, controller='post')
810        eq_('http://www.example.com:8080/blog/view/4', url_for(qualified=True, controller='blog', action='view', id=4))
811
812
813    def test_with_route_names(self):
814        m = self.con.mapper
815        m.minimization = True
816        self.con.mapper_dict = {}
817        m.connect('home', '', controller='blog', action='splash')
818        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
819        m.create_regs(['content','blog','admin/comments'])
820
821        assert_raises(Exception, url_for, controller='content', action='view')
822        assert_raises(Exception, url_for, controller='content')
823        assert_raises(Exception, url_for, controller='admin/comments')
824        eq_('/category', url_for('category_home'))
825        eq_('/category/food', url_for('category_home', section='food'))
826        assert_raises(Exception, url_for, 'home', controller='content')
827        eq_('/', url_for('home'))
828
829    def test_with_route_names_and_nomin(self):
830        m = self.con.mapper
831        m.minimization = False
832        self.con.mapper_dict = {}
833        m.connect('home', '', controller='blog', action='splash')
834        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
835        m.create_regs(['content','blog','admin/comments'])
836
837        assert_raises(Exception, url_for, controller='content', action='view')
838        assert_raises(Exception, url_for, controller='content')
839        assert_raises(Exception, url_for, controller='admin/comments')
840        eq_('/category/home', url_for('category_home'))
841        eq_('/category/food', url_for('category_home', section='food'))
842        assert_raises(Exception, url_for, 'home', controller='content')
843        eq_('/', url_for('home'))
844
845    def test_with_route_names_and_defaults(self):
846        m = self.con.mapper
847        self.con.mapper_dict = {}
848        m.connect('home', '', controller='blog', action='splash')
849        m.connect('category_home', 'category/:section', controller='blog', action='view', section='home')
850        m.connect('building', 'building/:campus/:building/alljacks', controller='building', action='showjacks')
851        m.create_regs(['content','blog','admin/comments','building'])
852
853        self.con.mapper_dict = dict(controller='building', action='showjacks', campus='wilma', building='port')
854        assert_raises(Exception, url_for)
855        eq_('/building/wilma/port/alljacks', url_for(controller='building', action='showjacks', campus='wilma', building='port'))
856        eq_('/', url_for('home'))
857
858    def test_with_resource_route_names(self):
859        m = Mapper()
860        self.con.mapper = m
861        self.con.mapper_dict = {}
862        m.resource('message', 'messages', member={'mark':'GET'}, collection={'rss':'GET'})
863        m.create_regs(['messages'])
864
865        assert_raises(Exception, url_for, controller='content', action='view')
866        assert_raises(Exception, url_for, controller='content')
867        assert_raises(Exception, url_for, controller='admin/comments')
868        eq_('/messages', url_for('messages'))
869        eq_('/messages/rss', url_for('rss_messages'))
870        eq_('/messages/4', url_for('message', id=4))
871        eq_('/messages/4/edit', url_for('edit_message', id=4))
872        eq_('/messages/4/mark', url_for('mark_message', id=4))
873        eq_('/messages/new', url_for('new_message'))
874
875        eq_('/messages.xml', url_for('formatted_messages', format='xml'))
876        eq_('/messages/rss.xml', url_for('formatted_rss_messages', format='xml'))
877        eq_('/messages/4.xml', url_for('formatted_message', id=4, format='xml'))
878        eq_('/messages/4/edit.xml', url_for('formatted_edit_message', id=4, format='xml'))
879        eq_('/messages/4/mark.xml', url_for('formatted_mark_message', id=4, format='xml'))
880        eq_('/messages/new.xml', url_for('formatted_new_message', format='xml'))
881
882    def test_with_resource_route_names_and_nomin(self):
883        m = Mapper()
884        self.con.mapper = m
885        self.con.mapper_dict = {}
886        m.minimization = False
887        m.resource('message', 'messages', member={'mark':'GET'}, collection={'rss':'GET'})
888        m.create_regs(['messages'])
889
890        assert_raises(Exception, url_for, controller='content', action='view')
891        assert_raises(Exception, url_for, controller='content')
892        assert_raises(Exception, url_for, controller='admin/comments')
893        eq_('/messages', url_for('messages'))
894        eq_('/messages/rss', url_for('rss_messages'))
895        eq_('/messages/4', url_for('message', id=4))
896        eq_('/messages/4/edit', url_for('edit_message', id=4))
897        eq_('/messages/4/mark', url_for('mark_message', id=4))
898        eq_('/messages/new', url_for('new_message'))
899
900        eq_('/messages.xml', url_for('formatted_messages', format='xml'))
901        eq_('/messages/rss.xml', url_for('formatted_rss_messages', format='xml'))
902        eq_('/messages/4.xml', url_for('formatted_message', id=4, format='xml'))
903        eq_('/messages/4/edit.xml', url_for('formatted_edit_message', id=4, format='xml'))
904        eq_('/messages/4/mark.xml', url_for('formatted_mark_message', id=4, format='xml'))
905        eq_('/messages/new.xml', url_for('formatted_new_message', format='xml'))
906
907
908if __name__ == '__main__':
909    unittest.main()
910else:
911    def bench_gen(withcache = False):
912        m = Mapper(explicit=False)
913        m.connect('', controller='articles', action='index')
914        m.connect('admin', controller='admin/general', action='index')
915
916        m.connect('admin/comments/article/:article_id/:action/:id', controller = 'admin/comments', action = None, id=None)
917        m.connect('admin/trackback/article/:article_id/:action/:id', controller='admin/trackback', action=None, id=None)
918        m.connect('admin/content/:action/:id', controller='admin/content')
919
920        m.connect('xml/:action/feed.xml', controller='xml')
921        m.connect('xml/articlerss/:id/feed.xml', controller='xml', action='articlerss')
922        m.connect('index.rdf', controller='xml', action='rss')
923
924        m.connect('articles', controller='articles', action='index')
925        m.connect('articles/page/:page', controller='articles', action='index', requirements = {'page':'\d+'})
926
927        m.connect('articles/:year/:month/:day/page/:page', controller='articles', action='find_by_date', month = None, day = None,
928                            requirements = {'year':'\d{4}', 'month':'\d{1,2}','day':'\d{1,2}'})
929        m.connect('articles/category/:id', controller='articles', action='category')
930        m.connect('pages/*name', controller='articles', action='view_page')
931        con = Config()
932        con.mapper = m
933        con.host = 'www.test.com'
934        con.protocol = 'http'
935        con.mapper_dict = {'controller':'xml','action':'articlerss'}
936
937        if withcache:
938            m.urlcache = {}
939        m._create_gens()
940        n = 5000
941        start = time.time()
942        for x in range(1,n):
943            url_for(controller='/articles', action='index', page=4)
944            url_for(controller='admin/general', action='index')
945            url_for(controller='admin/comments', action='show', article_id=2)
946
947            url_for(controller='articles', action='find_by_date', year=2004, page=1)
948            url_for(controller='articles', action='category', id=4)
949            url_for(id=2)
950        end = time.time()
951        ts = time.time()
952        for x in range(1,n*6):
953            pass
954        en = time.time()
955        total = end-start-(en-ts)
956        per_url = total / (n*6)
957        print("Generation (%s URLs) RouteSet" % (n*6))
958        print("%s ms/url" % (per_url*1000))
959        print("%s urls/s\n" % (1.00/per_url))
960