1# -*- coding: utf-8 -*-
2"""
3    jinja2.tests
4    ~~~~~~~~~~~~
5
6    Jinja test functions. Used with the "is" operator.
7
8    :copyright: (c) 2017 by the Jinja Team.
9    :license: BSD, see LICENSE for more details.
10"""
11import re
12from collections import Mapping
13from jinja2.runtime import Undefined
14from jinja2._compat import text_type, string_types, integer_types
15import decimal
16
17number_re = re.compile(r'^-?\d+(\.\d+)?$')
18regex_type = type(number_re)
19
20
21test_callable = callable
22
23
24def test_odd(value):
25    """Return true if the variable is odd."""
26    return value % 2 == 1
27
28
29def test_even(value):
30    """Return true if the variable is even."""
31    return value % 2 == 0
32
33
34def test_divisibleby(value, num):
35    """Check if a variable is divisible by a number."""
36    return value % num == 0
37
38
39def test_defined(value):
40    """Return true if the variable is defined:
41
42    .. sourcecode:: jinja
43
44        {% if variable is defined %}
45            value of variable: {{ variable }}
46        {% else %}
47            variable is not defined
48        {% endif %}
49
50    See the :func:`default` filter for a simple way to set undefined
51    variables.
52    """
53    return not isinstance(value, Undefined)
54
55
56def test_undefined(value):
57    """Like :func:`defined` but the other way round."""
58    return isinstance(value, Undefined)
59
60
61def test_none(value):
62    """Return true if the variable is none."""
63    return value is None
64
65
66def test_lower(value):
67    """Return true if the variable is lowercased."""
68    return text_type(value).islower()
69
70
71def test_upper(value):
72    """Return true if the variable is uppercased."""
73    return text_type(value).isupper()
74
75
76def test_string(value):
77    """Return true if the object is a string."""
78    return isinstance(value, string_types)
79
80
81def test_mapping(value):
82    """Return true if the object is a mapping (dict etc.).
83
84    .. versionadded:: 2.6
85    """
86    return isinstance(value, Mapping)
87
88
89def test_number(value):
90    """Return true if the variable is a number."""
91    return isinstance(value, integer_types + (float, complex, decimal.Decimal))
92
93
94def test_sequence(value):
95    """Return true if the variable is a sequence. Sequences are variables
96    that are iterable.
97    """
98    try:
99        len(value)
100        value.__getitem__
101    except:
102        return False
103    return True
104
105
106def test_equalto(value, other):
107    """Check if an object has the same value as another object:
108
109    .. sourcecode:: jinja
110
111        {% if foo.expression is equalto 42 %}
112            the foo attribute evaluates to the constant 42
113        {% endif %}
114
115    This appears to be a useless test as it does exactly the same as the
116    ``==`` operator, but it can be useful when used together with the
117    `selectattr` function:
118
119    .. sourcecode:: jinja
120
121        {{ users|selectattr("email", "equalto", "foo@bar.invalid") }}
122
123    .. versionadded:: 2.8
124    """
125    return value == other
126
127
128def test_sameas(value, other):
129    """Check if an object points to the same memory address than another
130    object:
131
132    .. sourcecode:: jinja
133
134        {% if foo.attribute is sameas false %}
135            the foo attribute really is the `False` singleton
136        {% endif %}
137    """
138    return value is other
139
140
141def test_iterable(value):
142    """Check if it's possible to iterate over an object."""
143    try:
144        iter(value)
145    except TypeError:
146        return False
147    return True
148
149
150def test_escaped(value):
151    """Check if the value is escaped."""
152    return hasattr(value, '__html__')
153
154
155def test_greaterthan(value, other):
156    """Check if value is greater than other."""
157    return value > other
158
159
160def test_lessthan(value, other):
161    """Check if value is less than other."""
162    return value < other
163
164
165TESTS = {
166    'odd':              test_odd,
167    'even':             test_even,
168    'divisibleby':      test_divisibleby,
169    'defined':          test_defined,
170    'undefined':        test_undefined,
171    'none':             test_none,
172    'lower':            test_lower,
173    'upper':            test_upper,
174    'string':           test_string,
175    'mapping':          test_mapping,
176    'number':           test_number,
177    'sequence':         test_sequence,
178    'iterable':         test_iterable,
179    'callable':         test_callable,
180    'sameas':           test_sameas,
181    'equalto':          test_equalto,
182    'escaped':          test_escaped,
183    'greaterthan':      test_greaterthan,
184    'lessthan':         test_lessthan
185}
186