def test_localvars_assignments_with_args_declaration(self): def _convert(input): return tenjin.Template(input=input).script if spec("args declaration exists before text then local vars assignments apprears at the same line with text."): input = r""" <?py # coding: utf-8 ?> <?py #@ARGS items ?> <p> <?py x = 10 ?> </p> """[1:] expected = r""" # coding: utf-8 items = _context.get('items'); _extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''<p>\n''', )); x = 10 _extend(('''</p>\n''', )); """[1:] ok (_convert(input)) == expected if spec("args declaration exists before statement then local vars assignments apprears at the same line with args declaration."): input = r""" <?py # coding: utf-8 ?> <?py #@ARGS items ?> <?py x = 10 ?> """[1:] expected = r""" # coding: utf-8 _extend=_buf.extend;_to_str=to_str;_escape=escape; items = _context.get('items'); x = 10 """[1:] ok (_convert(input)) == expected if spec("'from __future__' statement exists then skip it."): input = r""" <?py from __future__ import with_statement ?> <?py # coding: utf-8 ?> <?py #@ARGS item ?> item=${item} """[1:] expected = r""" from __future__ import with_statement # coding: utf-8 item = _context.get('item'); _extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''item=''', _escape(_to_str(item)), '''\n''', )); """[1:] ok (_convert(input)) == expected input = r""" <?py from __future__ import with_statement ?> <?py for item in items: ?> <p>${item}</p> <?py #endfor ?> """[1:] expected = r""" from __future__ import with_statement _extend=_buf.extend;_to_str=to_str;_escape=escape; for item in items: _extend((''' <p>''', _escape(_to_str(item)), '''</p>\n''', )); #endfor """[1:] ok (_convert(input)) == expected
def test_hook_context(self): e = tenjin.Engine() ctx = {} e.hook_context(ctx) if spec("add engine itself into context data."): ok (ctx.get('_engine')).is_(e) if spec("add include() method into context data."): ok (ctx.get('include')) == (e.include)
def test_read(self): if spec("if file exists, return file content and mtime"): ts = float(int(time.time())) - 1.0 os.utime('_views/layout.pyhtml', (ts, ts)) ret = self.loader.load('_views/layout.pyhtml') ok(ret) == ("<div>#{_content}</div>", ts) if spec("if file not exist, return None"): ret = self.loader.load('_views/layout2.pyhtml') ok(ret) == None
def test_find(self): if spec("if dirs provided then search template file from it."): ok(self.loader.find('index.pyhtml', self.dirs)) == '_views/blog/index.pyhtml' ok(self.loader.find('layout.pyhtml', self.dirs)) == '_views/layout.pyhtml' if spec("if dirs not provided then just return filename if file exists." ): ok(self.loader.find( '_views/index.pyhtml')) == '_views/index.pyhtml' if spec("if file not found then return None."): ok(self.loader.find('index2.pyhtml', self.dirs)) == None ok(self.loader.find('index2.pyhtml')) == None
def test__create_template(self): e1 = tenjin.Engine(path=['_views/blog', '_views']) t = None if spec("if input is not specified then just create empty template object."): t = e1._create_template(None) ok (t).is_a(tenjin.Template) ok (t.filename) == None ok (t.script) == None if spec("if input is specified then create template object and return it."): t = e1._create_template('<p>#{_content}</p>', '_views/layout.pyhtml') ok (t).is_a(tenjin.Template) ok (t.filename) == "_views/layout.pyhtml" ok (t.script) == lvars + "_extend(('''<p>''', _to_str(_content), '''</p>''', ));"
def test__preprocess(self): e1 = tenjin.Engine(preprocess=True) if spec("preprocess template and return result"): fpath = '_views/index.pyhtml' input, mtime = e1.loader.load(fpath) ret = e1._preprocess(input, fpath, {}, globals()) ok (ret) == "<<SOS>>"
def test_localvars_assignments_without_args_declaration(self): def _convert(input): return tenjin.Template(input=input).script if spec("add local vars assignments before text only once."): input = r""" <p> <?py x = 10 ?> </p> """[1:] expected = r""" _extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''<p>\n''', )); x = 10 _extend(('''</p>\n''', )); """[1:] ok (_convert(input)) == expected if spec("skips comments at the first lines."): input = r""" <?py # coding: utf-8 ?> <?py ### comment ?> <p> <?py x = 10 ?> </p> """[1:] expected = r""" # coding: utf-8 ### comment _extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''<p>\n''', )); x = 10 _extend(('''</p>\n''', )); """[1:] ok (_convert(input)) == expected if spec("adds local vars assignments before statements."): input = r""" <?py for item in items: ?> <?py x = 10 ?> <?py #endfor ?> </p> """[1:] expected = r""" _extend=_buf.extend;_to_str=to_str;_escape=escape; for item in items: x = 10 #endfor _extend(('''</p>\n''', )); """[1:] ok (_convert(input)) == expected
def test__get_template_from_cache(self): e1 = tenjin.Engine(path=['_views/blog', '_views'], postfix='.pyhtml') fpath = '_views/blog/index.pyhtml' cpath = fpath + '.cache' if spec("if template not found in cache, return None"): ret = e1._get_template_from_cache(cpath, fpath) ok (ret) == None t = tenjin.Template(fpath) e1.cache.set(fpath + '.cache', t) if spec("if checked within a sec, skip timestamp check."): #try: # t.timestamp = time.time() - 0.2 # #import pdb; pdb.set_trace() # tenjin.logger = DebugLogger() # ret = e1._get_template_from_cache(cpath, fpath) # msg = tenjin.logger.messages[0] # ok (msg.startswith("[TRACE] [tenjin.Engine] timestamp check skipped (")) == True #finally: # tenjin.logger = None pass if spec("if timestamp of template objectis same as file, return it."): t._last_checked_at = None t.timestamp = os.path.getmtime(fpath) ok (e1._get_template_from_cache(cpath, fpath)).is_(t) delta = JYTHON and 0.03 or 0.001 ok (t._last_checked_at).in_delta(time.time(), delta) if spec("if timestamp of template object is different from file, clear it"): t.timestamp = t.timestamp + 1 t._last_checked_at = None try: #import pdb; pdb.set_trace() tenjin.logger = DebugLogger() ret = e1._get_template_from_cache(cpath, fpath) msg = tenjin.logger.messages[0] ok (msg) == "[INFO] [tenjin.Engine] cache expired (filepath='_views/blog/index.pyhtml')" finally: tenjin.logger = None
def test_include(self): if spec("get local and global vars of caller."): pass if spec("get _context from caller's local vars."): pass if spec("if kwargs specified then add them into context."): pass if spec("get template object with context data and global vars."): pass if spec("if append_to_buf is true then add output to _buf."): pass if spec("if append_to_buf is false then don't add output to _buf."): pass if spec("render template and return output."): pass if spec("kwargs are removed from context data."): pass
def test_pp(self): if spec("'pp' paramater should be a list of preprocessor objects."): pp1 = tenjin.TemplatePreprocessor() pp2 = tenjin.TrimPreprocessor() pp3 = tenjin.JavaScriptPreprocessor(type="text/javascript") e = tenjin.Engine(pp=[pp1, pp2, pp3]) input = r""" <body> <div> <!-- #JS: render_items(items) --> <ul> <?js for (var i = 0; i < items.length; i++) { ?> <li>${i}</li> <?js } ?> </ul> <!-- #/JS --> </div> <script>#{{tenjin.JS_FUNC}}</script> </body> """[1:] expected = r""" <body> <div> <script type="text/javascript">function render_items(items){var _buf=''; _buf+='<ul>\n'; for (var i = 0; i < items.length; i++) { _buf+='<li>'+_E(i)+'</li>\n'; } _buf+='</ul>\n'; return _buf;};</script> </div> <script>function _S(x){return x==null?'':x;} function _E(x){return x==null?'':typeof(x)!=='string'?x:x.replace(/[&<>"']/g,_EF);} var _ET={'&':"&",'<':"<",'>':">",'"':""","'":"'"}; function _EF(c){return _ET[c];};</script> </body> """[1:] fname = 'tmp_123.pyhtml' f = open(fname, 'w'); f.write(input); f.close() try: t = e.get_template(fname) context = {} output = e.render(fname, context) ok (output) == expected finally: for x in glob(fname + '*'): os.unlink(x)
def test_timestamp(self): if spec("return mtime of file"): ts = float(int(time.time())) - 3.0 os.utime('_views/blog/index.pyhtml', (ts, ts)) ret = self.loader.timestamp('_views/blog/index.pyhtml') ok(ret) == ts
def test_abspath(self): if spec("return full-path of filepath"): ret = self.loader.abspath('_views/blog/index.pyhtml') ok(ret) == os.path.join(os.getcwd(), '_views/blog/index.pyhtml')
def test_add_expr(self): input = r""" not escape: #{var} escape: ${var} """ if spec("nothing is specified then both _to_str() and _escape() are used."): t = tenjin.Template() script = t.convert(input) expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend((''' not escape: ''', _to_str(var), ''' escape: ''', _escape(_to_str(var)), '''\n''', )); """ ok (script) == expected if spec("when tostrfunc is False then skips _to_str()."): expected = r"""_extend=_buf.extend;_to_str=False;_escape=escape; _extend((''' not escape: ''', (var), ''' escape: ''', _escape(var), '''\n''', )); """ t = tenjin.Template(tostrfunc=False) ok (t.convert(input)) == expected if spec("escapefunc is False then skips _escape()."): expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=False; _extend((''' not escape: ''', _to_str(var), ''' escape: ''', _to_str(var), '''\n''', )); """ t = tenjin.Template(escapefunc=False) ok (t.convert(input)) == expected if spec("both tostr and escapefunc are False then skips _to_str() and _escape()."): expected = r"""_extend=_buf.extend;_to_str=False;_escape=False; _extend((''' not escape: ''', (var), ''' escape: ''', (var), '''\n''', )); """ t = tenjin.Template(tostrfunc=False, escapefunc=False) ok (t.convert(input)) == expected if spec("get_expr_and_flags() returns flag_tostr=False then ignores _escape()."): tr = Tracer() def fn(orig, *args): expr, (flag_escape, flag_tostr) = orig(*args) return expr, (flag_escape, False) expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend((''' not escape: ''', (var), ''' escape: ''', _escape(var), '''\n''', )); """ t = tenjin.Template() tr.fake_method(t, get_expr_and_flags=fn) ok (t.convert(input)) == expected if spec("get_expr_and_flags() returns flag_escape=False then ignores _escape()."): tr = Tracer() def fn(orig, *args): expr, (flag_escape, flag_tostr) = orig(*args) return expr, (False, flag_tostr) expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend((''' not escape: ''', _to_str(var), ''' escape: ''', _to_str(var), '''\n''', )); """ t = tenjin.Template() tr.fake_method(t, get_expr_and_flags=fn) ok (t.convert(input)) == expected if spec("get_expr_and_flags() returns both flags False then ignores both _to_str() and _escape()."): tr = Tracer() def fn(orig, *args): expr, (flag_escape, flag_tostr) = orig(*args) return expr, (False, False) expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend((''' not escape: ''', (var), ''' escape: ''', (var), '''\n''', )); """ t = tenjin.Template() tr.fake_method(t, get_expr_and_flags=fn) ok (t.convert(input)) == expected
def test_get_template(self): e1 = tenjin.Engine(path=['_views/blog', '_views'], postfix='.pyhtml') filepath = '_views/blog/index.pyhtml' fullpath = os.getcwd() + filepath cachepath = fullpath + '.cache' assert not os.path.exists(cachepath) t = None if spec("return template object.") and \ spec("accept template_name such as ':index'."): t = e1.get_template(':index') ok (t).is_a(tenjin.Template) ok (t.filename) == filepath if spec("if template object is added by add_template(), return it."): tmp = tenjin.Template('foo.pyhtml', input="<<dummy>>") e1.add_template(tmp) ok (e1.get_template('foo.pyhtml')).is_(tmp) if spec("get filepath and fullpath of template"): e1._filepaths['index.pyhtml'] == (filepath, fullpath) if spec("if template file is not found then raise TemplateNotFoundError"): def f(): e1.get_template('index') ok (f).raises(tenjin.TemplateNotFoundError, "index: filename not found (path=['_views/blog', '_views']).") if spec("use full path as base of cache file path") and \ spec("get template object from cache"): ok (list(e1.cache.items.keys())) == ["%s/_views/blog/index.pyhtml.cache" % os.getcwd()] if spec("change template filename according to prefer_fullpath"): pass if spec("use full path as base of cache file path"): pass if spec("get template object from cache"): pass if spec("if template object is not found in cache or is expired..."): e1.cache.clear() ok (len(e1.cache.items)) == 0 tname = ':layout' fpath = '_views/layout.pyhtml' cpath = os.path.join(os.getcwd(), '_views/layout.pyhtml.cache') not_ok (cpath).exists() if spec("create template object."): t = e1.get_template(tname) ok (t).is_a(tenjin.Template) if spec("set timestamp and filename of template object."): ok (t.timestamp) == os.path.getmtime(filepath) ok (t.filename) == fpath delta = JYTHON and 0.03 or 0.003 ok (t._last_checked_at).in_delta(time.time(), delta) if spec("save template object into cache."): ok (cpath).exists() ok (len(e1.cache.items)) == 1 ok (e1.cache.items).contains(cpath)
def test_to_filename(self): engine = tenjin.Engine(prefix='user_', postfix='.pyhtml') if spec("if template_name starts with ':', add prefix and postfix to it."): ok (engine.to_filename(':list')) == 'user_list.pyhtml' if spec("if template_name doesn't start with ':', just return it."): ok (engine.to_filename('list')) == 'list'
def test_cachename(self): engine = tenjin.Engine() if spec("return cache file path"): ok (engine.cachename('foo.pyhtml')) == 'foo.pyhtml.cache'