[svn] added some more jinja unittests

--HG--
branch : trunk
diff --git a/CHANGES b/CHANGES
index 8d90efb..da46f59 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,7 +3,7 @@
 
 Version 1.1
 -----------
-(codename to be selected, release date unknown)
+(codename: sinka, released Jun 1, 2007)
 
 - blocks now support ``{{ super() }}`` to render the parent output.
 
@@ -110,9 +110,11 @@
 
 - improved ChoiceLoader error reporting (thanks to Bryan McLemore)
 
+- fixed extended slicing
+
 
 Version 1.0
 -----------
-(released Mar 23, 2007)
+(codename: siyutusan, released Mar 23, 2007)
 
 - Initial release
diff --git a/docs/src/altsyntax.txt b/docs/src/altsyntax.txt
index 9fb3b64..0f7242f 100644
--- a/docs/src/altsyntax.txt
+++ b/docs/src/altsyntax.txt
@@ -42,7 +42,7 @@
 
 .. sourcecode:: rhtml
 
-    <%# example eruby like configuration for jinja %>
+    <%# example eruby like configuration for Jinja %>
     <ul>
     <% for item in seq %>
       <li><%= item %></li>
@@ -63,7 +63,7 @@
 
 .. sourcecode:: html
 
-    <!--# example eruby like configuration for jinja -->
+    <!--# example SGML comment configuration for Jinja -->
     <ul>
     <!-- for item in seq -->
       <li>${item}</li>
@@ -98,6 +98,7 @@
 
 .. sourcecode:: smarty
 
+    {* example smarty-like configuration for Jinja *}
     {if something == 42}
         Something is the answer to all questions and stuff like that.
     {else}
diff --git a/jinja/datastructure.py b/jinja/datastructure.py
index 0f5d9e9..5946db8 100644
--- a/jinja/datastructure.py
+++ b/jinja/datastructure.py
@@ -65,6 +65,9 @@
         return self
     __deepcopy__ = __copy__
 
+    def __repr__(self):
+        return 'Undefined'
+
     def __reduce__(self):
         raise TypeError('undefined objects have to provide a __reduce__')
 
diff --git a/jinja/lexer.py b/jinja/lexer.py
index 45398db..2c452c5 100644
--- a/jinja/lexer.py
+++ b/jinja/lexer.py
@@ -51,7 +51,7 @@
     # braces and parenthesis
     '[', ']', '(', ')', '{', '}',
     # attribute access and comparison / logical operators
-    '.', ':', ',', '|', '==', '<', '>', '<=', '>=', '!=', '=',
+    '.', ':', ',', '|', '==', '<=', '>=', '<', '>', '!=', '=',
     ur'or\b', ur'and\b', ur'not\b', ur'in\b', ur'is\b'
 ]]))
 
@@ -275,7 +275,7 @@
                                 lineno += g.count('\n')
                             continue
                         # failure group
-                        elif isinstance(token, Failure):
+                        elif token.__class__ is Failure:
                             raise token(lineno, filename)
                         # bygroup is a bit more complex, in that case we
                         # yield for the current token the first named
diff --git a/jinja/parser.py b/jinja/parser.py
index 80f4c72..aba3725 100644
--- a/jinja/parser.py
+++ b/jinja/parser.py
@@ -353,7 +353,7 @@
                                           lineno, self.filename)
             # plural name without trailing "_"? that's a keyword
             if not name.endswith('_'):
-                raise TemplateSyntaxError('illegal use of keyword \'%s\' as'
+                raise TemplateSyntaxError('illegal use of keyword \'%s\' as '
                                           'identifier in translatable block.'
                                           % name, lineno, self.filename)
             name = name[:-1]
@@ -369,7 +369,7 @@
                (self.no_variable_block and next_token == 'block_end'):
                 raise TemplateSyntaxError('you cannot use variable '
                                           'expressions inside translatable '
-                                          'tags. apply filters in the'
+                                          'tags. apply filters in the '
                                           'trans header.', lineno,
                                           self.filename)
             buf.append('%%(%s)s' % name)
@@ -470,7 +470,7 @@
                                         continue
                                     block_name = block_name[:-1]
                                 raise TemplateSyntaxError('unknown directive'
-                                                          "'%s'" % block_name,
+                                                          " '%s'" % block_name,
                                                           lineno,
                                                           self.filename)
                         # we have something different and are in the
diff --git a/jinja/translators/python.py b/jinja/translators/python.py
index 34ae77c..bef7619 100644
--- a/jinja/translators/python.py
+++ b/jinja/translators/python.py
@@ -1002,8 +1002,8 @@
         Handle variable based attribute access foo['bar'].
         """
         if len(node.subs) != 1:
-            raise TemplateSyntaxError('attribute access requires one argument',
-                                      node.lineno,
+            raise TemplateSyntaxError('attribute access requires one '
+                                      'argument', node.lineno,
                                       node.filename)
         assert node.flags != 'OP_DELETE', 'wtf? do we support that?'
         if node.subs[0].__class__ is ast.Sliceobj:
@@ -1209,7 +1209,4 @@
         """
         Extended Slice access.
         """
-        args = []
-        for n in node.nodes:
-            args.append(self.handle_node(n))
-        return '[%s]' % ':'.join(args)
+        return '[%s]' % ':'.join([self.handle_node(n) for n in node.nodes])
diff --git a/jinja/utils.py b/jinja/utils.py
index 1359226..d9608eb 100644
--- a/jinja/utils.py
+++ b/jinja/utils.py
@@ -63,7 +63,9 @@
 except NameError:
     def sorted(seq, reverse=False):
         rv = list(seq)
-        rv.sort(reverse=reverse)
+        rv.sort()
+        if reverse:
+            rv.reverse()
         return rv
 
 #: function types
@@ -460,7 +462,7 @@
         for name, f in filters:
             if f in strip:
                 continue
-            doc = '\n'.join('    ' + x for x in (getdoc(f) or '').splitlines())
+            doc = '\n'.join(['    ' + x for x in (getdoc(f) or '').splitlines()])
             result.append('`%s`\n\n%s' % (name, doc))
         return '\n\n'.join(result)
     filters.jinja_context_callable = True
@@ -478,7 +480,7 @@
         for name, f in tests:
             if f in strip:
                 continue
-            doc = '\n'.join('    ' + x for x in (getdoc(f) or '').splitlines())
+            doc = '\n'.join(['    ' + x for x in (getdoc(f) or '').splitlines()])
             result.append('`%s`\n\n%s' % (name, doc))
         return '\n\n'.join(result)
     tests.jinja_context_callable = True
diff --git a/setup.py b/setup.py
index b457c45..a0be447 100644
--- a/setup.py
+++ b/setup.py
@@ -45,7 +45,7 @@
 
 setup(
     name = 'Jinja',
-    version = '1.0',
+    version = '1.1',
     url = 'http://jinja.pocoo.org/',
     license = 'BSD',
     author = 'Armin Ronacher',
diff --git a/tests/test_parser.py b/tests/test_parser.py
index d9d75c0..1c8851d 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -40,6 +40,8 @@
     {item}
 {-endfor}'''
 
+BALANCING = '''{{{'foo':'bar'}.foo}}'''
+
 
 def test_no_variable_block():
     env = Environment('{%', '%}', None, None)
@@ -74,3 +76,8 @@
     env = Environment('{', '}', '{', '}', '{*', '*}')
     tmpl = env.from_string(SMARTY_SYNTAX)
     assert tmpl.render(seq=range(5)) == '01234'
+
+
+def test_balancing(env):
+    tmpl = env.from_string(BALANCING)
+    assert tmpl.render() == 'bar'
diff --git a/tests/test_security.py b/tests/test_security.py
index 5e0099d..95d3371 100644
--- a/tests/test_security.py
+++ b/tests/test_security.py
@@ -44,4 +44,8 @@
 Traceback (most recent call last):
     ...
 TemplateSyntaxError: can't assign to expression. (line 1)
+>>> env.from_string("{% for foo, bar.baz in seq %}...{% endfor %}")
+Traceback (most recent call last):
+    ...
+TemplateSyntaxError: can't assign to expression. (line 1)
 '''
diff --git a/tests/test_syntax.py b/tests/test_syntax.py
new file mode 100644
index 0000000..79aaf2f
--- /dev/null
+++ b/tests/test_syntax.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+"""
+    unit test for expression syntax
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+
+CALL = '''{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}'''
+SLICING = '''{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}'''
+ATTR = '''{{ foo.bar }}|{{ foo['bar'] }}'''
+SUBSCRIPT = '''{{ foo[0] }}|{{ foo[-1] }}'''
+KEYATTR = '''{{ {'items': 'foo'}.items }}|{{ {}.items() }}'''
+TUPLE = '''{{ () }}'''
+MATH = '''{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}'''
+DIV = '''{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}'''
+UNARY = '''{{ +3 }}|{{ -3 }}'''
+COMPARE = '''{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|{{ 2 == 2 }}|{{ 1 <= 1 }}'''
+LITERALS = '''{{ [] }}|{{ {} }}|{{ '' }}'''
+BOOL = '''{{ true and false }}|{{ false or true }}|{{ not false }}'''
+
+
+def test_call():
+    from jinja import Environment
+    env = Environment()
+    env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
+    tmpl = env.from_string(CALL)
+    assert tmpl.render() == 'abdfh'
+
+
+def test_slicing(env):
+    tmpl = env.from_string(SLICING)
+    assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+
+
+def test_attr(env):
+    tmpl = env.from_string(ATTR)
+    assert tmpl.render(foo={'bar': 42}) == '42|42'
+
+
+def test_subscript(env):
+    tmpl = env.from_string(SUBSCRIPT)
+    assert tmpl.render(foo=[0, 1, 2]) == '0|2'
+
+
+def test_keyattr(env):
+    tmpl = env.from_string(KEYATTR)
+    assert tmpl.render() == 'foo|[]'
+
+
+def test_tuple(env):
+    tmpl = env.from_string(TUPLE)
+    assert tmpl.render() == '[]'
+
+
+def test_math(env):
+    tmpl = env.from_string(MATH)
+    assert tmpl.render() == '1.5|8'
+
+
+def test_div(env):
+    tmpl = env.from_string(DIV)
+    assert tmpl.render() == '1|1.5|1'
+
+
+def test_unary(env):
+    tmpl = env.from_string(UNARY)
+    assert tmpl.render() == '3|-3'
+
+
+def test_compare(env):
+    tmpl = env.from_string(COMPARE)
+    assert tmpl.render() == 'True|True|True|True|True'
+
+
+def test_literals(env):
+    tmpl = env.from_string(LITERALS)
+    assert tmpl.render() == '[]|{}|'
+
+
+def test_bool(env):
+    tmpl = env.from_string(BOOL)
+    assert tmpl.render() == 'False|True|True'
diff --git a/tests/test_various.py b/tests/test_various.py
index 6f449a4..cea56b8 100644
--- a/tests/test_various.py
+++ b/tests/test_various.py
@@ -6,6 +6,7 @@
     :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+from jinja.exceptions import TemplateSyntaxError
 
 KEYWORDS = '''\
 {{ with }}
@@ -31,7 +32,11 @@
 LIGHTKW = '''{{ call }}'''
 UNPACKING = '''{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}'''
 RAW = '''{% raw %}{{ FOO }} and {% BAR %}{% endraw %}'''
-CALL = '''{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}'''
+CONST = '''{{ true }}|{{ false }}|{{ none }}|{{ undefined }}|\
+{{ none is defined }}|{{ undefined is defined }}'''
+CONSTASS1 = '''{% set true = 42 %}'''
+CONSTASS2 = '''{% for undefined in seq %}{% endfor %}'''
+
 
 def test_keywords(env):
     env.from_string(KEYWORDS)
@@ -70,14 +75,6 @@
     assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d
 
 
-def test_call():
-    from jinja import Environment
-    env = Environment()
-    env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
-    tmpl = env.from_string(CALL)
-    assert tmpl.render() == 'abdfh'
-
-
 def test_stringfilter(env):
     from jinja.filters import stringfilter
     f = stringfilter(lambda f, x: f + x)
@@ -88,3 +85,18 @@
     from jinja.filters import simplefilter
     f = simplefilter(lambda f, x: f + x)
     assert f(42)(env, None, 23) == 65
+
+
+def test_const(env):
+    tmpl = env.from_string(CONST)
+    assert tmpl.render() == 'True|False|||True|False'
+
+
+def test_const_assign(env):
+    for tmpl in CONSTASS1, CONSTASS2:
+        try:
+            env.from_string(tmpl)
+        except TemplateSyntaxError:
+            pass
+        else:
+            raise AssertionError('expected syntax error')