def test_dict_call(): template = '''{{ dict(x=\ndict(\na=1, b=2), y=a) }}''' call_ast = parse(template).find(nodes.Call) rtype, struct = visit_call( call_ast, Context(predicted_struct=Unknown.from_ast(call_ast))) expected_rtype = Dictionary( { 'x': Dictionary( { 'a': Number(linenos=[3], constant=True, value=1), 'b': Number(linenos=[3], constant=True, value=2) }, linenos=[2], constant=True), 'y': Unknown(label='a', linenos=[3]), }, linenos=[1], constant=True) assert rtype == expected_rtype expected_struct = Dictionary({ 'a': Unknown(label='a', linenos=[3]), }) assert struct == expected_struct
def test_basics_2(): template = ''' {% if test1 %} {% if test2 %} {% set d = {'x': 123, a: z.qwerty} %} {% else %} {% set d = {'x': 456, a: z.gsom} %} {% endif %} {% endif %} {% if d %} {{ d.x }} {% endif %} {{ z.gsom }} ''' struct = infer(template) expected_struct = Dictionary({ 'a': Scalar(label='a', linenos=[4, 6]), 'test1': Unknown(label='test1', linenos=[2]), 'test2': Unknown(label='test2', linenos=[3]), 'z': Dictionary(data={ 'qwerty': Unknown(label='qwerty', linenos=[4]), 'gsom': Scalar(label='gsom', linenos=[6, 12]), }, label='z', linenos=[4, 6, 12]), }) assert struct == expected_struct
def test_basics_13(): config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_INTEGER_TYPE = 'tuple' template = ''' {% for x in xs %} {{ x[2] }} {{ x[3] }} {% endfor %} ''' struct = infer(template, config) expected_struct = Dictionary({ 'xs': List(Tuple(( Unknown(label=None, linenos=[]), Unknown(label=None, linenos=[]), Scalar(label=None, linenos=[3]), Scalar(label=None, linenos=[4]), ), label='x', linenos=[3, 4]), label='xs', linenos=[2]) }) assert struct == expected_struct
def test_boolean_conditions_setting_1(): template = ''' {% if x %} Hello! {% endif %} {{ 'Hello!' if y else '' }} ''' config_1 = Config() struct = infer(template, config_1) expected_struct = Dictionary({ 'x': Unknown(label='x', linenos=[2]), 'y': Unknown(label='y', linenos=[5]), }) assert struct == expected_struct infer('{% if [] %}{% endif %}', config_1) # make sure it doesn't raise config_2 = Config(BOOLEAN_CONDITIONS=True) struct = infer(template, config_2) expected_struct = Dictionary({ 'x': Boolean(label='x', linenos=[2]), 'y': Boolean(label='y', linenos=[5]), }) assert struct == expected_struct with pytest.raises(UnexpectedExpression) as e: infer('{% if [] %}{% endif %}', config_2) # make sure this does raise assert str(e.value) == ( 'conflict on the line 1\n' 'got: AST node jinja2.nodes.List of structure [<unknown>]\n' 'expected structure: <boolean>')
def test_assign_1(): template = '''{% set a = b %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'a': Unknown(label='a', linenos=[1], constant=True), 'b': Unknown(label='b', linenos=[1]), }) assert struct == expected_struct
def test_compare_1(): template = '{{ a < b < c }}' ast = parse(template).find(nodes.Compare) rtype, struct = visit_compare(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'a': Unknown(label='a', linenos=[1]), 'b': Unknown(label='b', linenos=[1]), 'c': Unknown(label='c', linenos=[1]), }) assert struct == expected_struct
def test_reverse_filter(): template = '{{ x|reverse }}' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == Unknown(label='x', linenos=[1]) expected_struct = Dictionary({ 'x': Unknown(label='x', linenos=[1]), }) assert struct == expected_struct
def test_unique_filter(): template = '{{ values|unique }}' ast = parse(template).find(nodes.Filter) unknown_ctx = Context(predicted_struct=Unknown.from_ast(ast)) rtype, struct = visit_filter(ast, unknown_ctx) assert rtype == Unknown(label='values', linenos=[1]) assert struct == Dictionary({ 'values': List(Unknown(), label='values', linenos=[1]), })
def test_compare_2(): template = '{{ a + b[1] - c == 4 == x }}' ast = parse(template).find(nodes.Compare) rtype, struct = visit_compare(ast, get_scalar_context(ast)) # TODO make customizable expected_struct = Dictionary({ 'a': Unknown(label='a', linenos=[1]), 'b': List(Unknown(linenos=[1]), label='b', linenos=[1]), 'c': Unknown(label='c', linenos=[1]), 'x': Unknown(label='x', linenos=[1]), }) assert struct == expected_struct
def test_ignore_all_unknown_filter(): template = '{{ x|foo|bar|baz }}' cfg = config.default_config cfg.IGNORE_UNKNOWN_FILTERS = True ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast), None, cfg) assert rtype == Unknown(label='x', linenos=[1]) expected_struct = Dictionary({ 'x': Unknown(label='x', linenos=[1]), }) assert struct == expected_struct
def test_assignment(): template = ''' {% set args = ['foo'] if foo else [] %} {% set args = args + ['bar'] %} {% set args = args + (['zork'] if zork else []) %} f({{ args|join(sep) }}); ''' struct = infer(template) expected_struct = Dictionary({ 'foo': Unknown(label='foo', linenos=[2]), 'zork': Unknown(label='zork', linenos=[4]), 'sep': String(label='sep', linenos=[5]) }) assert struct == expected_struct
def test_if_2(): template = ''' {% if z > x > y %} {% endif %} {% if x == y and x == 'asd' and z == 5 %} {% endif %} {{ x }} ''' struct = infer_from_ast(parse(template)) expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[2, 4, 6]), 'y': Unknown(label='y', linenos=[2, 4]), 'z': Unknown(label='z', linenos=[2, 4]), }) assert struct == expected_struct
def test_1(): template = ''' {%- if x is undefined %} {{ test }} {%- endif %} {%- if y is undefined %} {% set y = 123 %} {%- endif %} {%- if y is defined %} {{ y }} {%- endif %} {%- if z is undefined %} {{ z }} {%- endif %} ''' struct = infer(template) expected_struct = Dictionary({ 'x': Unknown(label='x', checked_as_undefined=True, linenos=[2]), 'test': Scalar(label='test', linenos=[3]), 'y': Number(label='y', may_be_defined=True, linenos=[6, 7, 10, 11]), 'z': Scalar(label='z', linenos=[14, 15]), }) assert struct == expected_struct
def test_getitem_3(): template = '''{{ a[3] }}''' ast = parse(template).find(nodes.Getitem) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_INTEGER_TYPE = 'tuple' rtype, struct = visit_getitem(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': Tuple([ Unknown(), Unknown(), Unknown(), Scalar(linenos=[1]), ], label='a', linenos=[1]), }) assert struct == expected_struct
def test_filter_chaining(): template = '''{{ (xs|first|last).gsom|sort|length }}''' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'xs': List(List(Dictionary( { 'gsom': List(Unknown(), label='gsom', linenos=[1]), }, linenos=[1]), linenos=[1]), label='xs', linenos=[1]), }) assert struct == expected_struct template = '''{{ x|list|sort|first }}''' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[1]), }) assert struct == expected_struct template = '''{{ x|first|list }}''' ast = parse(template).find(nodes.Filter) with pytest.raises(UnexpectedExpression): visit_filter(ast, get_scalar_context(ast))
def test_length_filter(): ast = parse('{{ xs|length }}').find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == Number(label='xs', linenos=[1]) assert struct == Dictionary({ 'xs': List(Unknown(), label='xs', linenos=[1]), })
def test_basics_1(): template = ''' {% set d = {'x': 123, a: z.qwerty} %} {{ d.x }} ''' struct = infer(template) expected_struct = Dictionary({ 'a': Scalar(label='a', linenos=[2]), 'z': Dictionary(label='z', data={ 'qwerty': Unknown(label='qwerty', linenos=[2]), }, linenos=[2]), }) assert struct == expected_struct template = ''' {% set d = {'x': 123, a: z.qwerty} %} {{ d.x.field }} ''' with pytest.raises(MergeException): infer(template) template = ''' {% set x = '123' %} {{ x.test }} ''' with pytest.raises(MergeException): infer(template) template = ''' {% set a = {'x': 123} %} {% set b = {a: 'test'} %} ''' with pytest.raises(MergeException): infer(template)
def test_basics_15(): # 1. Accept no unknown filter (default behavior) config = Config() template = ''' {% for item in items %} {{ item.attr1|lower }} {{ item.attr2|bar }} {% endfor %} ''' with pytest.raises(InvalidExpression) as e: infer(template, config) assert 'line 4: unknown filter "bar"' == str(e.value) # 2. Accept all unknown filters config = Config() config.IGNORE_UNKNOWN_FILTERS = True template = ''' {% for item in items %} {{ item.attr1|lower }} {{ item.attr2|bar }} {% endfor %} ''' struct = infer(template, config) expected_struct = Dictionary({ 'items': List(Dictionary({ 'attr1': String(label='attr1', linenos=[3]), 'attr2': Unknown(label='attr2', linenos=[4]) }, label='item', linenos=[3, 4]), label='items', linenos=[2]), }) assert struct == expected_struct
def test_basics_3(): template = ''' {% if x %} {% set x = '123' %} {% else %} {% set x = '456' %} {% endif %} {{ x }} ''' struct = infer(template) expected_struct = Dictionary({ 'x': String(label='x', linenos=[2, 3, 5, 7]), }) assert struct == expected_struct template = ''' {% if z %} {% set x = '123' %} {% else %} {% set x = '456' %} {% endif %} {{ x }} ''' struct = infer(template) expected_struct = Dictionary({ 'z': Unknown(label='z', linenos=[2]), }) assert struct == expected_struct
def test_str_method_calls(): template = '''{{ x.endswith(suffix) }}''' call_ast = parse(template).find(nodes.Call) rtype, struct = visit_call(call_ast, get_scalar_context(call_ast)) expected_rtype = Boolean() assert rtype == expected_rtype expected_struct = Dictionary({ 'x': String(label='x', linenos=[1]), # TODO suffix must be in struct too }) assert struct == expected_struct template = '''{{ x.split(separator) }}''' call_ast = parse(template).find(nodes.Call) ctx = Context(return_struct_cls=Unknown, predicted_struct=Unknown.from_ast(call_ast)) rtype, struct = visit_call(call_ast, ctx) expected_rtype = List(String()) assert rtype == expected_rtype expected_struct = Dictionary({ 'x': String(label='x', linenos=[1]), 'separator': String(label='separator', linenos=[1]), }) assert struct == expected_struct
def test_elif(): template = ''' {% if kenny.sick %} Kenny is sick. {% elif kenny.dead %} You killed Kenny! You bastard!!! {% else %} Kenny looks okay --- so far {% endif %} ''' struct = infer_from_ast(parse(template)) expected_struct = Dictionary({ 'kenny': Dictionary({ 'sick': Unknown(label='sick', linenos=[2]), 'dead': Unknown(label='dead', linenos=[4]), },label='kenny', linenos=[2, 4]), }) assert struct == expected_struct
def test_basics_6(): template = ''' {% for row in items|batch(3, ' ') %} {% endfor %} ''' struct = infer(template) expected_struct = Dictionary({ 'items': List(Unknown(), label='items', linenos=[2]), }) assert struct == expected_struct
def test_basics_9(): template = ''' {% set xs = items|batch(3, ' ') %} {{ xs[0][0] }} ''' struct = infer(template) expected_struct = Dictionary({ 'items': List(Unknown(), label='items', linenos=[2]), # TODO it should be Scalar }) assert struct == expected_struct
def test_length_filter(): for filter in ('count', 'length'): template = '{{ xs|' + filter + ' }}' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == Number(label='xs', linenos=[1]) assert struct == Dictionary({ 'xs': List(Unknown(), label='xs', linenos=[1]), })
def test_ignore_some_unknown_filter(): cfg = config.default_config cfg.IGNORE_UNKNOWN_FILTERS = ('foo', 'bar', 'baz') # 1. Check that it works when all the filter names are given template = '{{ x|foo|bar|baz }}' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast), None, cfg) assert rtype == Unknown(label='x', linenos=[1]) expected_struct = Dictionary({ 'x': Unknown(label='x', linenos=[1]), }) assert struct == expected_struct # 2. Check that an exception is raised for a filter whose name is not in the list template = '{{ x|foo|bar|baz|boz }}' ast = parse(template).find(nodes.Filter) with pytest.raises(InvalidExpression) as e: visit_filter(ast, get_scalar_context(ast), None, cfg) assert 'line 1: unknown filter "boz"' == str(e.value)
def test_test_2(): template = '''{{ x is string }}''' ast = parse(template).find(nodes.Test) rtype, struct = visit_test(ast, get_scalar_context(ast)) expected_struct = Dictionary({'x': Unknown(label='x', linenos=[1])}) assert struct == expected_struct template = '{{ x is unknown_filter }}' ast = parse(template).find(nodes.Test) with pytest.raises(InvalidExpression) as e: visit_test(ast, get_scalar_context(ast)) assert 'line 1: unknown test "unknown_filter"' in str(e.value)
def test_boolean_conditions_setting_2(): config = Config(BOOLEAN_CONDITIONS=True) template = ''' {% if x == 'test' %} Hello! {% endif %} ''' struct = infer(template, config) expected_struct = Dictionary({ 'x': Unknown(label='x', linenos=[2]), }) assert struct == expected_struct
def test_lipsum_call(): template = '{{ lipsum(n) }}' ast = parse(template).find(nodes.Call) rtype, struct = visit_call(ast, Context(predicted_struct=Unknown())) expected_rtype = String() assert rtype == expected_rtype expected_struct = Dictionary({ 'n': Scalar(label='n', linenos=[1]), # TODO must be Number }) assert struct == expected_struct
def test_range_call(): template = '{{ range(n) }}' ast = parse(template).find(nodes.Call) rtype, struct = visit_call(ast, Context(predicted_struct=Unknown())) expected_rtype = List(Number()) assert rtype == expected_rtype expected_struct = Dictionary({ 'n': Number(label='n', linenos=[1]), }) assert struct == expected_struct
def test_batch_and_slice_filters(): for filter in ('batch', 'slice'): template = '{{ items|' + filter + '(3, " ") }}' ast = parse(template).find(nodes.Filter) unknown_ctx = Context(predicted_struct=Unknown.from_ast(ast)) rtype, struct = visit_filter(ast, unknown_ctx) expected_rtype = List(List(Unknown(), linenos=[1]), linenos=[1]) assert rtype == expected_rtype expected_struct = Dictionary({ 'items': List(Unknown(), label='items', linenos=[1]), }) assert struct == expected_struct scalar_ctx = Context(predicted_struct=Scalar.from_ast(ast)) with pytest.raises(UnexpectedExpression) as e: visit_filter(ast, scalar_ctx) assert str(e.value) == ( 'conflict on the line 1\n' 'got: AST node jinja2.nodes.Filter of structure [[<unknown>]]\n' 'expected structure: <scalar>')
def test_dict_call(): template = '''{{ dict(x=\ndict(\na=1, b=2), y=a) }}''' call_ast = parse(template).find(nodes.Call) rtype, struct = visit_call( call_ast, Context(predicted_struct=Unknown.from_ast(call_ast))) expected_rtype = Dictionary({ 'x': Dictionary({ 'a': Number(linenos=[3], constant=True), 'b': Number(linenos=[3], constant=True) }, linenos=[2], constant=True), 'y': Unknown(label='a', linenos=[3]), }, linenos=[1], constant=True) assert rtype == expected_rtype expected_struct = Dictionary({ 'a': Unknown(label='a', linenos=[3]), }) assert struct == expected_struct
def test_batch_and_slice_filters(): for filter in ('batch', 'slice'): template = '{{ items|' + filter + '(3, " ") }}' ast = parse(template).find(nodes.Filter) unknown_ctx = Context(predicted_struct=Unknown.from_ast(ast)) rtype, struct = visit_filter(ast, unknown_ctx) expected_rtype = List(List(Unknown(), linenos=[1]), linenos=[1]) assert rtype == expected_rtype expected_struct = Dictionary({ 'items': List(Unknown(), label='items', linenos=[1]), }) assert struct == expected_struct scalar_ctx = Context(predicted_struct=Scalar.from_ast(ast)) with pytest.raises(UnexpectedExpression) as e: visit_filter(ast, scalar_ctx) assert str(e.value) == ('conflict on the line 1\n' 'got: AST node jinja2.nodes.Filter of structure [[<unknown>]]\n' 'expected structure: <scalar>')