1# -*- coding: utf-8 -*-
2from nose import SkipTest
3import shutil, os
4import json
5import tg
6from tg.configuration import milestones
7#tg.configuration.reqlocal_config.push_process_config({})
8
9from tests.test_stack import TestConfig, app_from_config
10from tg.configuration.hooks import _TGGlobalHooksNamespace
11from tg.util import Bunch
12from tg._compat import PY3, im_func
13from tg.renderers.genshi import GenshiRenderer
14from tg import expose
15from tg import TGController, AppConfig
16from webtest import TestApp
17from datetime import datetime
18
19try:
20    from tgext.chameleon_genshi import ChameleonGenshiRenderer
21except ImportError:
22    ChameleonGenshiRenderer = None
23
24def setup_noDB(genshi_doctype=None, genshi_method=None, genshi_encoding=None, extra=None,
25               extra_init=None):
26    base_config = TestConfig(folder='rendering', values={
27        'use_sqlalchemy': False,
28       'use_legacy_renderer': False,
29       # this is specific to mako  to make sure inheritance works
30       'use_dotted_templatenames': False,
31       'use_toscawidgets': False,
32       'use_toscawidgets2': False
33    })
34
35    deployment_config = {}
36    # remove previous option value to avoid using the old one
37    tg.config.pop('templating.genshi.doctype', None)
38    if genshi_doctype:
39        deployment_config['templating.genshi.doctype'] = genshi_doctype
40    tg.config.pop('templating.genshi.method', None)
41    if genshi_method:
42        deployment_config['templating.genshi.method'] = genshi_method
43    tg.config.pop('templating.genshi.encoding', None)
44    if genshi_encoding:
45        deployment_config['templating.genshi.encoding'] = genshi_encoding
46
47    deployment_config.update(extra or {})
48
49    if extra_init is not None:
50        extra_init(base_config)
51
52    return app_from_config(base_config, deployment_config)
53
54def test_default_genshi_renderer():
55    app = setup_noDB()
56    resp = app.get('/')
57    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
58        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
59    assert "Welcome" in resp
60    assert "TurboGears" in resp
61
62def test_genshi_nameconstant():
63    from genshi.template.astutil import ASTCodeGenerator, parse
64    from tg.renderers.genshi import GenshiRenderer
65
66    # This checks genshi gets monkeypatched to fix it on Py34 if option is provided
67    GenshiRenderer.create(Bunch({
68        'templating.genshi.name_constant_patch': True,
69        'use_dotted_templatenames': False,
70        'auto_reload_templates': False,
71        'paths': Bunch({'templates': '/tmp'})
72    }), None)
73    assert hasattr(ASTCodeGenerator, 'visit_NameConstant')
74
75    astgen = ASTCodeGenerator(parse('range(10)', mode='eval'))
76    for n in (False, True, None):
77        astgen._new_line()
78        astgen.visit_NameConstant(Bunch(value=n))
79        line = str(astgen.line)
80        assert line == str(n), line
81
82    astgen._new_line()
83    try:
84        astgen.visit_NameConstant(Bunch(value='HELLO_WORLD'))
85    except Exception as e:
86        assert 'Unknown NameConstant' in str(e)
87    else:
88        assert False
89
90def test_genshi_doctype_html5():
91    app = setup_noDB(genshi_doctype='html5')
92    resp = app.get('/')
93    assert '<!DOCTYPE html>' in resp
94    assert "Welcome" in resp
95    assert "TurboGears" in resp
96
97def test_genshi_auto_doctype():
98    app = setup_noDB()
99    resp = app.get('/auto_doctype')
100    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
101        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
102    assert 'content="text/html; charset=utf-8"' in resp
103    assert "doctype generation" in resp
104    assert "<hr />" in resp
105    assert "<p>Rendered with Genshi.</p>" in resp
106
107def test_genshi_method_html():
108    app = setup_noDB(genshi_method='html')
109    resp = app.get('/auto_doctype')
110    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"'
111        ' "http://www.w3.org/TR/html4/loose.dtd">') in resp
112    assert 'content="text/html; charset=utf-8"' in resp
113    assert "doctype generation" in resp
114    assert "<hr>" in resp
115    assert "<p>Rendered with Genshi.</p>" in resp
116
117def test_genshi_method_xhtml():
118    app = setup_noDB(genshi_method='xhtml')
119    resp = app.get('/auto_doctype')
120    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
121        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
122    assert 'content="text/html; charset=utf-8"' in resp
123    assert "doctype generation" in resp
124    assert "<hr />" in resp
125    assert "<p>Rendered with Genshi.</p>" in resp
126
127def test_genshi_doctype_html():
128    app = setup_noDB(genshi_doctype='html')
129    resp = app.get('/auto_doctype')
130    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
131        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
132    assert 'content="text/html; charset=utf-8"' in resp
133    assert "doctype generation" in resp
134    assert "<hr>" in resp
135    assert "<p>Rendered with Genshi.</p>" in resp
136
137def test_genshi_doctype_html5():
138    app = setup_noDB(genshi_doctype='html5')
139    resp = app.get('/auto_doctype')
140    assert '<!DOCTYPE html>' in resp
141    assert 'content="text/html; charset=utf-8"' in resp
142    assert "doctype generation" in resp
143    assert "<hr>" in resp
144    assert "<p>Rendered with Genshi.</p>" in resp
145
146def test_genshi_doctype_xhtml_strict():
147    app = setup_noDB(genshi_doctype='xhtml-strict')
148    resp = app.get('/auto_doctype')
149    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
150        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') in resp
151    assert 'content="text/html; charset=utf-8"' in resp
152    assert "doctype generation" in resp
153    assert "<hr />" in resp
154    assert "<p>Rendered with Genshi.</p>" in resp
155
156def test_genshi_doctype_html_maps_to_xhtml():
157    app = setup_noDB(genshi_doctype={'text/html': ('xhtml', 'html')})
158    resp = app.get('/auto_doctype_html')
159    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
160        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') in resp
161    assert 'content="text/html; charset=utf-8"' in resp
162    assert "doctype generation" in resp
163    assert "<hr />" in resp
164    assert "<p>Rendered with Genshi.</p>" in resp
165
166def test_genshi_method_html_maps_to_xhtml():
167    app = setup_noDB(genshi_method={'text/html': ('xhtml', 'html')})
168    resp = app.get('/auto_doctype_html')
169    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
170        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
171    assert 'content="text/html; charset=utf-8"' in resp
172    assert "doctype generation" in resp
173    assert "<hr />" in resp
174    assert "<p>Rendered with Genshi.</p>" in resp
175
176def test_genshi_method_xml_overridden_by_content_type_html():
177    app = setup_noDB(genshi_method='xml')
178    resp = app.get('/auto_doctype_html')
179    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
180        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
181    assert 'content="text/html; charset=utf-8"' in resp
182    assert "doctype generation" in resp
183    assert "<hr>" in resp
184    assert "<p>Rendered with Genshi.</p>" in resp
185
186def test_genshi_method_xhtml_is_ok_with_content_type_html():
187    app = setup_noDB(genshi_method='xhtml')
188    resp = app.get('/auto_doctype_html')
189    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
190        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
191    assert 'content="text/html; charset=utf-8"' in resp
192    assert "doctype generation" in resp
193    assert "<hr />" in resp
194    assert "<p>Rendered with Genshi.</p>" in resp
195
196def test_genshi_doctype_xhtml_maps_to_html():
197    app = setup_noDB(
198        genshi_doctype={'application/xhtml+xml': ('html', 'xhtml')})
199    resp = app.get('/auto_doctype_xhtml')
200    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
201        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
202    assert 'content="application/xhtml+xml; charset=utf-8"' in resp
203    assert "doctype generation" in resp
204    assert "<hr />" in resp
205    assert "<p>Rendered with Genshi.</p>" in resp
206
207def test_genshi_method_xhtml_maps_to_html():
208    app = setup_noDB(
209        genshi_doctype={'application/xhtml+xml': ('html', 'xhtml')},
210        genshi_method={'application/xhtml+xml': ('html', 'xhtml')})
211    resp = app.get('/auto_doctype_xhtml')
212    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
213        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
214    assert 'content="application/xhtml+xml; charset=utf-8"' in resp
215    assert "doctype generation" in resp
216    assert "<hr>" in resp
217    assert "<p>Rendered with Genshi.</p>" in resp
218
219def test_genshi_method_xml_overridden_by_content_type_xhtml():
220    app = setup_noDB(genshi_method='xml')
221    resp = app.get('/auto_doctype_xhtml')
222    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
223        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') in resp
224    assert 'content="application/xhtml+xml; charset=utf-8"' in resp
225    assert "doctype generation" in resp
226    assert "<hr />" in resp
227    assert "<p>Rendered with Genshi.</p>" in resp
228
229def test_genshi_method_html_overridden_by_content_type_xhtml():
230    app = setup_noDB(genshi_method='html')
231    resp = app.get('/auto_doctype_xhtml')
232    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
233        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') in resp
234    assert 'content="application/xhtml+xml; charset=utf-8"' in resp
235    assert "doctype generation" in resp
236    assert "<hr />" in resp
237    assert "<p>Rendered with Genshi.</p>" in resp
238
239def test_genshi_explicit_no_doctype():
240    app = setup_noDB()
241    resp = app.get('/explicit_no_doctype')
242    assert 'DOCTYPE' not in resp
243    assert 'content="text/html; charset=utf-8"' in resp
244    assert "doctype generation" in resp
245    assert "<hr />" in resp
246    assert "<p>Rendered with Genshi.</p>" in resp
247
248def test_genshi_explicit_doctype_html():
249    app = setup_noDB(genshi_doctype='xhtml')
250    resp = app.get('/explicit_doctype_html')
251    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
252        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
253    assert 'content="text/html; charset=utf-8"' in resp
254    assert "doctype generation" in resp
255    assert "<hr>" in resp
256    assert "<p>Rendered with Genshi.</p>" in resp
257
258def test_genshi_explicit_doctype_xhtml():
259    app = setup_noDB(genshi_doctype='html')
260    resp = app.get('/explicit_doctype_xhtml')
261    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
262        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') in resp
263    assert 'content="text/html; charset=utf-8"' in resp
264    assert "doctype generation" in resp
265    assert "<hr />" in resp
266    assert "<p>Rendered with Genshi.</p>" in resp
267
268def test_html_priority_for_ie():
269    app = setup_noDB()
270    resp = app.get('/html_and_json', headers={'Accept':
271        'application/x-ms-application, image/jpeg, application/xaml+xml,'
272        ' image/gif, image/pjpeg, application/x-ms-xbap, */*'})
273    assert 'text/html' in str(resp), resp
274
275def test_genshi_foreign_characters():
276    app = setup_noDB()
277    resp = app.get('/foreign')
278    assert "Foreign Cuisine" in resp
279    assert "Crème brûlée with Käsebrötchen" in resp
280
281def test_genshi_inheritance():
282    app = setup_noDB()
283    resp = app.get('/genshi_inherits')
284    assert "Inheritance template" in resp
285    assert "Master template" in resp
286
287def test_genshi_sub_inheritance():
288    app = setup_noDB()
289    resp = app.get('/genshi_inherits_sub')
290    assert "Inheritance template" in resp
291    assert "Master template" in resp
292    assert "from sub-template: sub.tobeincluded" in resp
293
294def test_genshi_sub_inheritance_from_bottom():
295    app = setup_noDB()
296    resp = app.get('/genshi_inherits_sub_from_bottom')
297    assert "from sub-template: sub.frombottom" in resp
298    assert "Master template" in resp
299
300def test_chameleon_genshi_base():
301    if ChameleonGenshiRenderer is None:
302        raise SkipTest()
303
304    def add_chameleon_renderer(app_config):
305        app_config.register_rendering_engine(ChameleonGenshiRenderer)
306        app_config.renderers.append('chameleon_genshi')
307
308    app = setup_noDB(extra_init=add_chameleon_renderer)
309
310    # Manually add the exposition again as it was already discarded
311    # due to chameleon_genshi not being in the available renderes.
312    milestones.renderers_ready._reset()
313    from .controllers.root import RootController
314    controller = im_func(RootController.chameleon_genshi_index)
315    expose('chameleon_genshi:index.html')(controller)
316    milestones.renderers_ready.reach()
317
318    resp = app.get('/chameleon_genshi_index')
319    assert ("<p>TurboGears 2 is rapid web application development toolkit"
320        " designed to make your life easier.</p>") in resp
321
322def test_chameleon_genshi_inheritance():
323    if ChameleonGenshiRenderer is None:
324        raise SkipTest()
325
326    def add_chameleon_renderer(app_config):
327        app_config.register_rendering_engine(ChameleonGenshiRenderer)
328        app_config.renderers.append('chameleon_genshi')
329
330    try:
331        import lxml
332    except ImportError:
333        # match templates need lxml, but since they don're really work anyway
334        # (at least not fully compatible with Genshi), we just skip this test
335        return
336
337    app = setup_noDB(extra_init=add_chameleon_renderer)
338
339    milestones.renderers_ready._reset()
340    from .controllers.root import RootController
341    controller = im_func(RootController.chameleon_genshi_inherits)
342    expose('chameleon_genshi:genshi_inherits.html')(controller)
343    milestones.renderers_ready.reach()
344
345    try:
346        resp = app.get('/chameleon_genshi_inherits')
347    except NameError as e:
348        # known issue with chameleon.genshi 1.0
349        if 'match_templates' not in str(e):
350            raise
351    except AttributeError as e:
352        # known issue with chameleon.genshi 1.3
353        if 'XPathResult' not in str(e):
354            raise
355    else:
356        assert "Inheritance template" in resp
357        assert "Master template" in resp
358
359def test_jinja_autoload():
360    app = setup_noDB()
361
362    try:
363        resp = app.get('/jinja_autoload')
364        assert False
365    except Exception as e:
366        assert "no filter named 'polluting_function'" in str(e)
367
368def _test_jinja_inherits():
369    app = setup_noDB()
370    resp = app.get('/jinja_inherits')
371    assert "Welcome on my awsome homepage" in resp, resp
372
373def test_jinja_extensions():
374    base_config = TestConfig(folder = 'rendering',
375                             values = {'use_sqlalchemy': False,
376                                       'use_legacy_renderer': False,
377                                       # this is specific to mako
378                                       # to make sure inheritance works
379                                       'use_dotted_templatenames': False,
380                                       'renderers':['jinja'],
381                                       'jinja_extensions': ['jinja2.ext.do', 'jinja2.ext.i18n',
382                                                            'jinja2.ext.with_', 'jinja2.ext.autoescape'],
383                                       'use_toscawidgets': False,
384                                       'use_toscawidgets2': False
385                                       }
386                             )
387    app = app_from_config(base_config)
388    resp = app.get('/jinja_extensions')
389    assert "<b>Autoescape Off</b>" in resp, resp
390    assert "&lt;b&gt;Test Autoescape On&lt;/b&gt;" in resp, resp
391
392def test_jinja_buildin_filters():
393    app = setup_noDB()
394    resp = app.get('/jinja_buildins')
395    assert 'HELLO JINJA!' in resp, resp
396
397def test_jinja_custom_filters():
398    # Simple test filter to get a md5 hash of a string
399    def codify(value):
400        try:
401            from hashlib import md5
402        except ImportError:
403            from md5 import md5
404        string_hash = md5(value.encode('ascii'))
405        return string_hash.hexdigest()
406
407    base_config = TestConfig(folder = 'rendering',
408                             values = {'use_sqlalchemy': False,
409                                       'use_legacy_renderer': False,
410                                       # this is specific to mako
411                                       # to make sure inheritance works
412                                       'use_dotted_templatenames': False,
413                                       'renderers':['jinja'],
414                                       'jinja_filters': {'codify': codify},
415                                       'use_toscawidgets': False,
416                                       'use_toscawidgets2': False
417                                       }
418                             )
419    app = app_from_config(base_config)
420
421    try:
422        resp = app.get('/jinja_filters')
423    finally:
424        # Remove filters so we don't mess with other test units
425        tg.config.pop('jinja_filters')
426
427    assert '8bb23e0b574ecb147536efacc864891b' in resp, resp
428
429def test_jinja_autoload_filters():
430    app = setup_noDB()
431    resp = app.get('/jinja_filters')
432    assert '29464d5ffe8f8dba1782fffcd6ed9fca6ceb4742' in resp, resp
433
434def test_mako_renderer():
435    app = setup_noDB()
436    resp = app.get('/mako_index')
437    assert "<p>This is the mako index page</p>" in resp, resp
438
439def test_mako_renderer_compiled():
440    app = setup_noDB(extra={
441        'templating.mako.compiled_templates_dir': '_tg_tests_mako_compiled/dest'
442    })
443
444    resp = app.get('/mako_index')
445    assert "<p>This is the mako index page</p>" in resp, resp
446
447    assert os.path.exists('_tg_tests_mako_compiled')
448    shutil.rmtree('_tg_tests_mako_compiled', True)
449
450def test_mako_renderer_compiled_existing():
451    os.makedirs('_tg_tests_mako_compiled/dest')
452    test_mako_renderer_compiled()
453
454def test_mako_renderer_compiled_no_access():
455    os.makedirs('_tg_tests_mako_compiled')
456    os.makedirs('_tg_tests_mako_compiled/dest', mode=0o400)
457    test_mako_renderer_compiled()
458
459def test_mako_renderer_compiled_no_access_parent():
460    os.makedirs('_tg_tests_mako_compiled', mode=0o400)
461    test_mako_renderer_compiled()
462
463def test_mako_inheritance():
464    app = setup_noDB()
465    resp = app.get('/mako_inherits')
466    assert "inherited mako page" in resp, resp
467    assert "Inside parent template" in resp, resp
468
469def test_template_override():
470#    app = setup_noDB()
471    base_config = TestConfig(folder = 'rendering',
472                             values = {'use_sqlalchemy': False,
473                                       'use_legacy_renderer': False,
474                                       # this is specific to mako
475                                       # to make sure inheritance works
476                                       'use_dotted_templatenames': True,
477                                       'renderers':['genshi'],
478                                       'use_toscawidgets': False,
479                                       'use_toscawidgets2': False
480                                       }
481                             )
482    app = app_from_config(base_config)
483    r =app.get('/template_override')
484    assert "Not overridden" in r, r
485    r = app.get('/template_override', params=dict(override=True))
486    assert "This is overridden." in r, r
487    # now invoke the controller again without override,
488    # it should yield the old result
489    r = app.get('/template_override')
490    assert "Not overridden" in r, r
491
492def test_template_override_wts():
493#    app = setup_noDB()
494    base_config = TestConfig(folder = 'rendering',
495                             values = {'use_sqlalchemy': False,
496                                       'use_legacy_renderer': False,
497                                       # this is specific to mako
498                                       # to make sure inheritance works
499                                       'use_dotted_templatenames': True,
500                                       'renderers':['genshi'],
501                                       'use_toscawidgets': False,
502                                       'use_toscawidgets2': False
503                                       }
504                             )
505    app = app_from_config(base_config)
506    r = app.get('/template_override_wts', status=301) # ensure with_trailing_slash
507    r =app.get('/template_override_wts/')
508    assert "Not overridden" in r, r
509    r = app.get('/template_override_wts/', params=dict(override=True))
510    assert "This is overridden." in r, r
511    # now invoke the controller again without override,
512    # it should yield the old result
513    r = app.get('/template_override_wts/')
514    assert "Not overridden" in r, r
515
516def test_template_override_content_type():
517    base_config = TestConfig(folder = 'rendering',
518                             values = {'use_sqlalchemy': False,
519                                       'use_legacy_renderer': False,
520                                       # this is specific to mako
521                                       # to make sure inheritance works
522                                       'use_dotted_templatenames': True,
523                                       'renderers':['mako', 'genshi'],
524                                       'use_toscawidgets': False,
525                                       'use_toscawidgets2': False
526                                       }
527                             )
528    app = app_from_config(base_config)
529    r =app.get('/template_override_content_type')
530    assert r.content_type == 'text/javascript'
531    assert "Not overridden" in r, r
532    r = app.get('/template_override_content_type', params=dict(override=True))
533    assert r.content_type == 'text/javascript'
534    assert "This is overridden." in r, r
535    # now invoke the controller again without override,
536    # it should yield the old result
537    r = app.get('/template_override_content_type')
538    assert "Not overridden" in r, r
539
540def test_template_custom_format_default():
541    app = setup_noDB()
542    resp = app.get('/custom_format')
543    assert 'OK' in resp
544    assert resp.content_type == 'text/html'
545
546def test_template_custom_format_xml():
547    app = setup_noDB()
548    resp = app.get('/custom_format?format=xml')
549    assert 'xml' in resp
550    assert resp.content_type == 'text/xml'
551
552def test_template_custom_format_json():
553    app = setup_noDB()
554    resp = app.get('/custom_format?format=json')
555    assert 'json' in resp
556    assert resp.content_type == 'application/json'
557
558def test_template_custom_format_html():
559    app = setup_noDB()
560    resp = app.get('/custom_format?format=html')
561    assert 'html' in resp
562    assert resp.content_type == 'text/html'
563
564def test_template_custom_format_nonexisting():
565    app = setup_noDB()
566
567    try:
568        resp = app.get('/custom_format?format=csv')
569        assert False
570    except Exception as e:
571        assert 'not a valid custom_format' in str(e)
572
573def test_template_override_multiple_content_type():
574    app = setup_noDB()
575    resp = app.get('/template_override_multiple_content_type')
576    assert 'something' in resp
577
578    resp = app.get(
579        '/template_override_multiple_content_type',
580        params=dict(override=True))
581    assert 'This is the mako index page' in resp
582
583def test_override_template_on_noncontroller():
584    tg.override_template(None, 'this.is.not.a.template')
585
586def test_jinja2_manual_rendering():
587    app = setup_noDB()
588    tgresp = app.get('/jinja2_manual_rendering')
589    pyresp = app.get('/jinja2_manual_rendering?frompylons=1')
590    assert str(tgresp) == str(pyresp), str(tgresp) + '\n------\n' + str(pyresp)
591
592def test_no_template():
593    app = setup_noDB()
594    resp = app.get('/no_template_generator')
595    assert '1234' in resp, resp
596
597def test_genshi_manual_render_no_doctype():
598    app = setup_noDB()
599    resp = app.get('/genshi_manual_rendering_with_doctype')
600    assert 'DOCTYPE' not in resp, resp
601    assert "<hr />" in resp
602    assert 'content="text/html; charset=utf-8"' in resp
603    assert "<p>Rendered with Genshi.</p>" in resp
604
605def test_genshi_manual_render_auto_doctype():
606    app = setup_noDB()
607    resp = app.get('/genshi_manual_rendering_with_doctype?doctype=auto')
608    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
609        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') in resp
610    assert 'content="text/html; charset=utf-8"' in resp
611    assert "<hr />" in resp
612    assert "<p>Rendered with Genshi.</p>" in resp
613
614def test_genshi_manual_render_html_doctype():
615    app = setup_noDB()
616    resp = app.get('/genshi_manual_rendering_with_doctype?doctype=html')
617    assert ('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"'
618        ' "http://www.w3.org/TR/html4/strict.dtd">') in resp
619    assert 'content="text/html; charset=utf-8"' in resp
620    assert "<hr>" in resp
621    assert "<p>Rendered with Genshi.</p>" in resp
622
623def test_genshi_manual_render_svg_doctype():
624    app = setup_noDB()
625    resp = app.get('/genshi_manual_rendering_with_doctype?doctype=svg')
626    assert '<!DOCTYPE svg' in resp
627
628def test_genshi_methods_for_doctype():
629    assert GenshiRenderer.method_for_doctype('application/xml') == 'xhtml'
630
631def test_variable_provider():
632    app = setup_noDB(extra={'variable_provider': lambda: {'inject_this_var':5}})
633    resp = app.get('/get_tg_vars')
634    assert 'inject_this_var' in resp
635
636def test_index_dotted_with_forced_extension():
637    app = setup_noDB()
638    resp = app.get('/index_dotted_with_forced_extension')
639    assert 'Welcome to TurboGears' in resp
640    assert 'NOW: IT WORKS' in resp
641
642    # The purely kajiki version of this template doesn't have NOW,
643    # check it's actually like that otherwise we would pass the previous
644    # check even when it didn't resolve to the genshi template.
645    kresp = app.get('/kajiki_index_dotted')
646    assert 'Welcome to TurboGears' in kresp
647    assert 'NOW: IT WORKS' not in kresp
648
649def test_render_hooks():
650    old_hooks, tg.hooks = tg.hooks, _TGGlobalHooksNamespace()
651
652    calls = []
653    def render_call_hook(*args, **kw):
654        calls.append(1)
655
656    base_config = TestConfig(folder='rendering', values={
657        'use_sqlalchemy': False,
658        'use_legacy_renderer': False,
659        # this is specific to mako  to make sure inheritance works
660        'use_dotted_templatenames': False,
661        'use_toscawidgets': False,
662        'use_toscawidgets2': False
663    })
664
665    milestones._reset_all()
666    base_config.register_hook('before_render_call', render_call_hook)
667    base_config.register_hook('after_render_call', render_call_hook)
668    app = app_from_config(base_config, reset_milestones=False)
669    app.get('/')
670
671    try:
672        assert len(calls) == 2
673    finally:
674        tg.hooks = old_hooks
675
676
677class TestEngineDetection(object):
678    def setUp(self):
679        self.app = setup_noDB(genshi_doctype='html', extra={
680            'errorpage.enabled': True
681        })
682
683    def test_no_engine_for_content_type(self):
684        resp = self.app.get('/aborted_json', status=403)
685        assert '{"error":"value"}' in resp
686
687    def test_content_type_provided(self):
688        resp = self.app.get('/according_to_content_type?ctype=text/html')
689        assert '<p>SomeValue' in resp
690        resp = self.app.get('/according_to_content_type?ctype=application/json')
691        assert 'value": "SomeValue' in resp, resp
692
693
694class TestTemplateCaching(object):
695    def setUp(self):
696        base_config = TestConfig(folder='rendering', values={
697            'use_sqlalchemy': False,
698            'use_legacy_renderer': False,
699            # this is specific to mako  to make sure inheritance works
700            'use_dotted_templatenames': False,
701            'use_toscawidgets': False,
702            'use_toscawidgets2': False,
703            'cache_dir': '.'
704        })
705        self.app = app_from_config(base_config)
706
707    def test_basic(self):
708        resp = self.app.get('/template_caching')
709        current_date = resp.text.split('NOW:')[1].split('\n')[0].strip()
710
711        resp = self.app.get('/template_caching')
712        assert current_date in resp, (current_date, resp.body)
713
714    def test_default_type(self):
715        resp = self.app.get('/template_caching_default_type')
716        current_date = resp.text.split('NOW:')[1].split('\n')[0].strip()
717
718        resp = self.app.get('/template_caching_default_type')
719        assert current_date in resp, (current_date, resp.body)
720
721    def test_template_caching_options(self):
722        resp = self.app.get('/template_caching_options', params={'cache_type':'memory'})
723        resp = json.loads(resp.text)
724        assert resp['cls'] == 'MemoryNamespaceManager', resp
725
726        resp = self.app.get('/template_caching_options', params={'cache_expire':1})
727        resp = json.loads(resp.text)
728        assert resp['cls'] == 'NoImplementation', resp
729
730        resp = self.app.get('/template_caching_options', params={'cache_key':'TEST'})
731        resp = json.loads(resp.text)
732        assert resp['cls'] == 'NoImplementation', resp
733
734
735class TestJSONRendering(object):
736    def setUp(self):
737        base_config = TestConfig(folder='rendering', values={
738            'use_sqlalchemy': False,
739            'use_legacy_renderer': False,
740            # this is specific to mako  to make sure inheritance works
741            'use_dotted_templatenames': False,
742            'use_toscawidgets': False,
743            'use_toscawidgets2': False,
744            'cache_dir': '.',
745            'json.isodates': True
746        })
747        self.app = app_from_config(base_config)
748
749    def teardown(self):
750        milestones._reset_all()
751
752    def test_jsonp(self):
753        resp = self.app.get('/get_jsonp', params={'call': 'callme'})
754        assert 'callme({"value": 5});' in resp.text, resp
755
756    def test_jsonp_with_key(self):
757        resp = self.app.get('/get_jsonp_with_key', params={'call': 'callme'})
758        assert 'callme({"value": 5});' in resp.text, resp
759
760    def test_jsonp_missing_callback(self):
761        resp = self.app.get('/get_jsonp', status=400)
762        assert 'JSONP requires a "call" parameter with callback name' in resp.text, resp
763
764    def test_json_isodates_default(self):
765        resp = self.app.get('/get_json_isodates_default')
766        assert 'T' in resp.json_body['date']
767        assert resp.json_body['date'].startswith(datetime.utcnow().strftime('%Y-%m-%d'))
768
769    def test_json_isodates(self):
770        resp = self.app.get('/get_json_isodates_on')
771        assert 'T' in resp.json_body['date']
772        assert resp.json_body['date'].startswith(datetime.utcnow().strftime('%Y-%m-%d'))
773
774    def test_json_without_isodates(self):
775        resp = self.app.get('/get_json_isodates_off')
776        assert ' ' in resp.json_body['date'], resp
777
778    def test_json_lists_allowing(self):
779        resp = self.app.get('/get_json_list')
780        assert '[1, 2, 3]' == resp.text
781
782    def test_json_return_list(self):
783        try:
784            resp = self.app.get("/json_return_list")
785            assert False
786        except Exception as e:
787            assert 'Your Encoded object must be dict-like' in str(e), e
788