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_test_1(): template = '''{{ x is divisibleby (data.field) }}''' ast = parse(template).find(nodes.Test) rtype, struct = visit_test(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[1]), 'data': Dictionary({ 'field': Number(label='field', linenos=[1]), }, label='data', linenos=[1]) }) assert struct == expected_struct template = '''{{ x is divisibleby 3 }}''' ast = parse(template).find(nodes.Test) rtype, struct = visit_test(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[1]), }) assert struct == expected_struct
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_cond_expr(): template = '''{{ queue if queue is defined else 'wizard' }}''', ast = parse(template).find(nodes.CondExpr) rtype, struct = visit_cond_expr(ast, get_scalar_context(ast)) expected_struct = Dictionary( {'queue': Scalar(label='queue', linenos=[1], checked_as_defined=True)}) assert struct == expected_struct template = '''{{ queue if queue is undefined else 'wizard' }}''' ast = parse(template).find(nodes.CondExpr) rtype, struct = visit_cond_expr(ast, get_scalar_context(ast)) expected_struct = Dictionary({'queue': Scalar(label='queue', linenos=[1])}) assert struct == expected_struct
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_assign_2(): template = '''{% set y = "-" ~ y %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({'y': String(label='y', linenos=[1])}) assert struct == expected_struct
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_getitem_1(): template = '''{{ a['b']['c'][1]['d'][x] }}''' ast = parse(template).find(nodes.Getitem) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_VARIABLE_TYPE = 'list' rtype, struct = visit_getitem(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': Dictionary( { 'b': Dictionary( { 'c': List(Dictionary( { 'd': List(Scalar(linenos=[1]), label='d', linenos=[1]) }, linenos=[1]), label='c', linenos=[1]), }, label='b', linenos=[1]), }, label='a', linenos=[1]), 'x': Scalar(label='x', linenos=[1]), }) assert struct == expected_struct
def test_getattr_1(): template = '{{ (x or y).field.subfield[2].a }}' ast = parse(template).find(nodes.Getattr) rtype, struct = visit_getattr(ast, get_scalar_context(ast)) x_or_y_dict = { 'field': Dictionary( { 'subfield': List(Dictionary({'a': Scalar(label='a', linenos=[1])}, linenos=[1]), label='subfield', linenos=[1]), }, label='field', linenos=[1]), } expected_struct = Dictionary({ 'x': Dictionary(x_or_y_dict, label='x', linenos=[1]), 'y': Dictionary(x_or_y_dict, label='y', linenos=[1]) }) assert struct == expected_struct
def test_macro_visitor_1(): template = ''' {% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{value|e }}" size="{{ size }}"> {{ x }} {%- endmacro %} ''' ast = parse(template).find(nodes.Macro) macroses = {} struct = visit_macro(ast, macroses) expected_macro = Macro('input', [ ('name', Scalar(label='argument #1', linenos=[2])), ], [ ('value', String(label='argument "value"', linenos=[2])), ('type', String(label='argument "type"', linenos=[2])), ('size', Number(label='argument "size"', linenos=[2])), ]) macro = macroses['input'] assert macro.name == expected_macro.name assert macro.args == expected_macro.args assert macro.kwargs == expected_macro.kwargs expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[4]) }) assert struct == expected_struct
def test_macro_visitor_1(): template = ''' {% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{value|e }}" size="{{ size }}"> {{ x }} {%- endmacro %} ''' ast = parse(template).find(nodes.Macro) macroses = {} struct = visit_macro(ast, macroses) expected_macro = Macro('input', [ ('name', Scalar(label='argument #1', linenos=[2])), ], [ ('value', String(label='argument "value"', linenos=[2])), ('type', String(label='argument "type"', linenos=[2])), ('size', Number(label='argument "size"', linenos=[2])), ]) macro = macroses['input'] assert macro.name == expected_macro.name assert macro.args == expected_macro.args assert macro.kwargs == expected_macro.kwargs expected_struct = Dictionary({'x': Scalar(label='x', linenos=[4])}) assert struct == expected_struct
def test_cond_expr(): template = '''{{ queue if queue is defined else 'wizard' }}''', ast = parse(template).find(nodes.CondExpr) rtype, struct = visit_cond_expr(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'queue': Scalar(label='queue', linenos=[1], checked_as_defined=True) }) assert struct == expected_struct template = '''{{ queue if queue is undefined else 'wizard' }}''' ast = parse(template).find(nodes.CondExpr) rtype, struct = visit_cond_expr(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'queue': Scalar(label='queue', linenos=[1]) }) assert struct == expected_struct
def test_slice(): template = '''{{ xs[a:2:b] }}''' ast = parse(template).find(nodes.Getitem) rtype, struct = visit_getitem(ast, get_scalar_context(ast)) assert struct == Dictionary({ 'xs': List(Scalar(linenos=[1]), label='xs', linenos=[1]), 'a': Number(label='a', linenos=[1]), 'b': Number(label='b', linenos=[1]), })
def test_assign_2(): template = '''{% set y = "-" ~ y %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'y': String(label='y', linenos=[1]) }) assert struct == expected_struct
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_assign_6(): template = ''' {%- set weights = [ ('A', {'data': 0.3}), ('B', {'data': 0.9}, 1, 2), ] %} ''' ast = parse(template).find(nodes.Assign) with pytest.raises(MergeException): visit_assign(ast)
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_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_getitem_2(): template = '''{{ a[z] }}''' ast = parse(template).find(nodes.Getitem) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_VARIABLE_TYPE = 'dictionary' rtype, struct = visit_getitem(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': Dictionary(label='a', linenos=[1]), 'z': Scalar(label='z', linenos=[1]), }) assert struct == expected_struct
def test_getattr_2(): template = '{{ data.field.subfield }}' ast = parse(template).find(nodes.Getattr) rtype, struct = visit_getattr(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'data': Dictionary({ 'field': Dictionary({ 'subfield': Scalar(label='subfield', linenos=[1]), }, label='field', linenos=[1]), }, label='data', linenos=[1]), }) assert struct == expected_struct
def test_assign_4(): template = '''{% set a, b = 1, {'gsom': 'gsom', z: z} %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'a': Number(label='a', linenos=[1], constant=True, value=1), 'b': Dictionary(data={ 'gsom': String(linenos=[1], constant=True, value='gsom'), }, label='b', linenos=[1], constant=True), 'z': Scalar(label='z', linenos=[1]), }) assert struct == expected_struct
def test_assign_4(): template = '''{% set a, b = 1, {'gsom': 'gsom', z: z} %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'a': Number(label='a', linenos=[1], constant=True), 'b': Dictionary(data={ 'gsom': String(linenos=[1], constant=True), }, label='b', linenos=[1], constant=True), 'z': Scalar(label='z', linenos=[1]), }) 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_macro_visitor_2(): template = ''' {% macro input(name, value='') -%} {{ value.x }} {%- endmacro %} ''' ast = parse(template).find(nodes.Macro) macroses = {} with pytest.raises(MergeException) as e: visit_macro(ast, macroses) assert str(e.value) == ('variable "argument "value"" (used as string on lines 2) conflicts with ' 'variable "value" (used as dictionary on lines: 3)')
def test_for_1(): template = ''' {% for x in a.b %} {{ x }} {% endfor %} ''' ast = parse(template).find(nodes.For) struct = visit_for(ast) expected_struct = Dictionary({ 'a': Dictionary({ 'b': List(Scalar(label='x', linenos=[3]), label='b', linenos=[2]) }, label='a', linenos=[2]), }) 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_macro_visitor_2(): template = ''' {% macro input(name, value='') -%} {{ value.x }} {%- endmacro %} ''' ast = parse(template).find(nodes.Macro) macroses = {} with pytest.raises(MergeException) as e: visit_macro(ast, macroses) assert str(e.value) == ( 'variable "argument "value"" (used as string on lines 2) conflicts with ' 'variable "value" (used as dictionary on lines: 3)')
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_getattr_1(): template = '{{ (x or y).field.subfield[2].a }}' ast = parse(template).find(nodes.Getattr) rtype, struct = visit_getattr(ast, get_scalar_context(ast)) x_or_y_dict = { 'field': Dictionary({ 'subfield': List(Dictionary({ 'a': Scalar(label='a', linenos=[1]) }, linenos=[1]), label='subfield', linenos=[1]), }, label='field', linenos=[1]), } expected_struct = Dictionary({ 'x': Dictionary(x_or_y_dict, label='x', linenos=[1]), 'y': Dictionary(x_or_y_dict, label='y', 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_if_1(): template = ''' {% if (x or y) and not z %} {{ x }} {{ z.field }} {% endif %} ''' ast = parse(template).find(nodes.If) struct = visit_if(ast) expected_struct = Dictionary({ 'z': Dictionary({ 'field': Scalar(label='field', linenos=[4]), }, label='z', linenos=[2, 4]), 'x': Scalar(label='x', linenos=[2, 3]), 'y': Unknown(label='y', linenos=[2]), }) assert struct == expected_struct
def test_assign_5(): template = ''' {%- set weights = [ ('A', {'data': 0.3}), ('B', {'data': 0.9}), ] %} ''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'weights': List(Tuple([ String(linenos=[3, 4], constant=True), Dictionary({ 'data': Number(linenos=[3, 4], constant=True) }, linenos=[3, 4], constant=True), ], linenos=[3, 4], constant=True), label='weights', linenos=[2], constant=True) }) assert struct == expected_struct
def test_for_2(): template = ''' {% for x in xs %} {{ x }} {% for y in ys %} {{ loop.index0 }} {% endfor %} {{ loop.length }} {% endfor %} ''' ast = parse(template) struct = infer_from_ast(ast) expected_struct = Dictionary({ 'xs': List(Scalar(label='x', linenos=[3]), label='xs', linenos=[2]), 'ys': List(Unknown(linenos=[4]), label='ys', linenos=[4]), }) assert struct == expected_struct
def test_getitem_1(): template = '''{{ a['b']['c'][1]['d'][x] }}''' ast = parse(template).find(nodes.Getitem) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_VARIABLE_TYPE = 'list' rtype, struct = visit_getitem(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': Dictionary({ 'b': Dictionary({ 'c': List(Dictionary({ 'd': List(Scalar(linenos=[1]), label='d', linenos=[1]) }, linenos=[1]), label='c', linenos=[1]), }, label='b', linenos=[1]), }, label='a', linenos=[1]), 'x': Scalar(label='x', linenos=[1]), }) assert struct == expected_struct
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_for_3(): template = ''' {% for a, b in list %} {{ a.field }} {{ b }} {% endfor %} ''' ast = parse(template).find(nodes.For) struct = visit_for(ast) expected_struct = Dictionary({ 'list': List(Tuple(( Dictionary({ 'field': Scalar(label='field', linenos=[3]) }, label='a', linenos=[3]), Scalar(label='b', linenos=[4]) ), linenos=[2]), label='list', linenos=[2]) }) assert struct == expected_struct
def test_getattr_3(): template = '''{{ a[z][1:\nn][1].x }}''' ast = parse(template).find(nodes.Getattr) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_VARIABLE_TYPE = 'list' rtype, struct = visit_getattr(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': List(List(List(Dictionary({'x': Scalar(label='x', linenos=[2])}, linenos=[2]), linenos=[2]), linenos=[1]), label='a', linenos=[1]), 'z': Scalar(label='z', linenos=[1]), 'n': Number(label='n', linenos=[2]) }) assert struct == expected_struct
def test_getattr_3(): template = '''{{ a[z][1:\nn][1].x }}''' ast = parse(template).find(nodes.Getattr) config = Config() config.TYPE_OF_VARIABLE_INDEXED_WITH_VARIABLE_TYPE = 'list' rtype, struct = visit_getattr(ast, get_scalar_context(ast), {}, config) expected_struct = Dictionary({ 'a': List( List( List( Dictionary({ 'x': Scalar(label='x', linenos=[2]) }, linenos=[2]), linenos=[2]), linenos=[1] ), label='a', linenos=[1] ), 'z': Scalar(label='z', linenos=[1]), 'n': Number(label='n', linenos=[2]) }) assert struct == expected_struct
def test_assign_3(): template = '''{% set a, b = {'a': 1, 'b': 2} %}''' ast = parse(template).find(nodes.Assign) with pytest.raises(UnexpectedExpression): visit_assign(ast)
def test_raise_on_unknown_call(): for template in ('{{ x.some_unknown_f() }}', '{{ xxx() }}'): call_ast = parse(template).find(nodes.Call) with pytest.raises(InvalidExpression) as e: visit_call(call_ast, get_scalar_context(call_ast)) assert 'call is not supported' in str(e.value)