def test_replace_builtins(source, original, result): original_ast = vy_ast.parse_to_ast(source.format(original)) target_ast = vy_ast.parse_to_ast(source.format(result)) folding.replace_builtin_functions(original_ast) assert vy_ast.compare_nodes(original_ast, target_ast)
def test_replace_literal_ops(): test_ast = vy_ast.parse_to_ast("[not True, True and False, True or False]") expected_ast = vy_ast.parse_to_ast("[False, False, True]") folding.replace_literal_ops(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_replace_subscripts_simple(): test_ast = vy_ast.parse_to_ast("[foo, bar, baz][1]") expected_ast = vy_ast.parse_to_ast("bar") folding.replace_subscripts(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_replace_binop_nested(): test_ast = vy_ast.parse_to_ast("((6 + (2**4)) * 4) / 2") expected_ast = vy_ast.parse_to_ast("44") folding.replace_literal_ops(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_replace_constant_no(source): unmodified_ast = vy_ast.parse_to_ast(source) folded_ast = vy_ast.parse_to_ast(source) folding.replace_constant(folded_ast, "FOO", vy_ast.Int(value=31337), True) assert vy_ast.compare_nodes(unmodified_ast, folded_ast)
def test_replace_builtin_constant_no(source): unmodified_ast = vy_ast.parse_to_ast(source) folded_ast = vy_ast.parse_to_ast(source) folding.replace_builtin_constants(folded_ast) assert vy_ast.compare_nodes(unmodified_ast, folded_ast)
def test_replace_binop_simple(): test_ast = vy_ast.parse_to_ast("1 + 2") expected_ast = vy_ast.parse_to_ast("3") folding.replace_literal_ops(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_integration(): test_ast = vy_ast.parse_to_ast("[1+2, 6+7][8-8]") expected_ast = vy_ast.parse_to_ast("3") folding.fold(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_replace_subscripts_nested(): test_ast = vy_ast.parse_to_ast("[[0, 1], [2, 3], [4, 5]][2][1]") expected_ast = vy_ast.parse_to_ast("5") folding.replace_subscripts(test_ast) assert vy_ast.compare_nodes(test_ast, expected_ast)
def test_node_does_not_exist(): test_tree = vy_ast.parse_to_ast("foo = 42") old_node = test_tree.body[0].target new_node = vy_ast.parse_to_ast("42").body[0].value with pytest.raises(CompilerPanic): test_tree.replace_in_tree(new_node, old_node)
def test_replace_userdefined_constant_no(source): source = f"FOO: constant(int128) = 42\n{source}" unmodified_ast = vy_ast.parse_to_ast(source) folded_ast = vy_ast.parse_to_ast(source) folding.replace_user_defined_constants(folded_ast) assert vy_ast.compare_nodes(unmodified_ast, folded_ast)
def test_assumptions(): # ASTs generated seperately from the same source should compare equal test_tree = vy_ast.parse_to_ast("foo = 42") expected_tree = vy_ast.parse_to_ast("foo = 42") assert vy_ast.compare_nodes(test_tree, expected_tree) # ASTs generated seperately with different source should compare not-equal test_tree = vy_ast.parse_to_ast("foo = 42") expected_tree = vy_ast.parse_to_ast("bar = 666") assert not vy_ast.compare_nodes(test_tree, expected_tree)
def test_list_replacement_similar_nodes(): test_tree = vy_ast.parse_to_ast("foo = [1, 1, 1, 1, 1]") expected_tree = vy_ast.parse_to_ast("foo = [1, 1, 31337, 1, 1]") old_node = test_tree.body[0].value.elements[2] new_node = vy_ast.parse_to_ast("31337").body[0].value test_tree.replace_in_tree(old_node, new_node) assert vy_ast.compare_nodes(test_tree, expected_tree)
def test_simple_replacement(): test_tree = vy_ast.parse_to_ast("foo = 42") expected_tree = vy_ast.parse_to_ast("bar = 42") old_node = test_tree.body[0].target new_node = vy_ast.parse_to_ast("bar").body[0].value test_tree.replace_in_tree(old_node, new_node) assert vy_ast.compare_nodes(test_tree, expected_tree)
def test_cannot_replace_twice(): test_tree = vy_ast.parse_to_ast("foo = 42") old_node = test_tree.body[0].target new_node = vy_ast.parse_to_ast("42").body[0].value test_tree.replace_in_tree(old_node, new_node) with pytest.raises(CompilerPanic): test_tree.replace_in_tree(old_node, new_node)
def test_replace_userdefined_attribute(source): preamble = f"ADDR: constant(address) = {dummy_address}" l_source = f"{preamble}\n{source[0]}" r_source = f"{preamble}\n{source[1]}" l_ast = vy_ast.parse_to_ast(l_source) folding.replace_user_defined_constants(l_ast) r_ast = vy_ast.parse_to_ast(r_source) assert vy_ast.compare_nodes(l_ast, r_ast)
def test_parents_children(): test_tree = vy_ast.parse_to_ast("foo = 42") old_node = test_tree.body[0].target parent = old_node.get_ancestor() new_node = vy_ast.parse_to_ast("bar").body[0].value test_tree.replace_in_tree(old_node, new_node) assert old_node.get_ancestor() == new_node.get_ancestor() assert old_node not in parent.get_children() assert new_node in parent.get_children() assert old_node not in test_tree.get_descendants() assert new_node in test_tree.get_descendants()
def test_nested(get_contract, assert_tx_failed, values, ops): variables = "abcdefghij" input_value = ",".join(f"{i}: decimal" for i in variables[: len(values)]) return_value = " ".join(f"{a} {b}" for a, b in zip(variables[: len(values)], ops)) return_value = return_value.rsplit(maxsplit=1)[0] source = f""" @public def foo({input_value}) -> decimal: return {return_value} """ contract = get_contract(source) literal_op = " ".join(f"{a} {b}" for a, b in zip(values, ops)) literal_op = literal_op.rsplit(maxsplit=1)[0] vyper_ast = vy_ast.parse_to_ast(literal_op) try: vy_ast.folding.replace_literal_ops(vyper_ast) expected = vyper_ast.body[0].value.value is_valid = True except ZeroDivisionException: # for division/modulus by 0, expect the contract call to revert is_valid = False if is_valid: assert contract.foo(*values) == expected else: assert_tx_failed(lambda: contract.foo(*values))
def test_binop_pow(): # raises because Vyper does not support decimal exponentiation vyper_ast = vy_ast.parse_to_ast(f"3.1337 ** 4.2") old_node = vyper_ast.body[0].value with pytest.raises(TypeMismatch): old_node.evaluate()
def test_no_tags_implies_notice(): code = """ ''' Because there is no tag, this docstring is handled as a notice. ''' @public def foo(): ''' This one too! ''' pass """ vyper_ast = parse_to_ast(code) global_ctx = GlobalContext.get_global_context(vyper_ast) userdoc, devdoc = parse_natspec(vyper_ast, global_ctx) assert userdoc == { "methods": { "foo()": { "notice": "This one too!" } }, "notice": "Because there is no tag, this docstring is handled as a notice.", } assert not devdoc
def test_returns(): code = """ @public def foo(bar: int128, baz: uint256) -> (int128, uint256): ''' @return value of bar @return value of baz ''' return bar, baz """ vyper_ast = parse_to_ast(code) global_ctx = GlobalContext.get_global_context(vyper_ast) _, devdoc = parse_natspec(vyper_ast, global_ctx) assert devdoc == { "methods": { "foo(int128,uint256)": { "returns": { "_0": "value of bar", "_1": "value of baz" } } } }
def extract_sigs(sig_code, interface_name=None): if sig_code["type"] == "vyper": interface_ast = [ i for i in vy_ast.parse_to_ast(sig_code["code"], contract_name=interface_name) # all the nodes visited by ModuleNodeVisitor. if isinstance( i, ( vy_ast.FunctionDef, vy_ast.EnumDef, vy_ast.EventDef, vy_ast.StructDef, vy_ast.InterfaceDef, # parsing import statements at this stage # causes issues with recursive imports # vy_ast.Import, # vy_ast.ImportFrom, ), ) or (isinstance(i, vy_ast.AnnAssign) and i.target.id != "implements") ] global_ctx = GlobalContext.get_global_context(interface_ast) return _get_external_signatures(global_ctx) elif sig_code["type"] == "json": return mk_full_signature_from_json(sig_code["code"]) else: raise Exception(( f"Unknown interface signature type '{sig_code['type']}' supplied. " "'vyper' & 'json' are supported"))
def _build_node(source): # docstring ensures string nodes are properly generated, not turned into docstrings source = f"""'I am a docstring.'\n{source}""" ast = vy_ast.parse_to_ast(source).body[0] if isinstance(ast, vy_ast.Expr): ast = ast.value return ast
def test_type_filter(): vyper_ast = vy_ast.parse_to_ast("[1, (2, (3, (4, 5.0), 'six')), 7, 0x08]") descendants = vyper_ast.get_descendants(vy_ast.Int) assert len(descendants) == 5 assert not next( (i for i in descendants if not isinstance(i, vy_ast.Int)), False)
def test_params(): code = """ @public def foo(bar: int128, baz: uint256, potato: bytes32): ''' @param bar a number @param baz also a number @dev we didn't document potato, but that's ok ''' pass """ vyper_ast = parse_to_ast(code) global_ctx = GlobalContext.get_global_context(vyper_ast) _, devdoc = parse_natspec(vyper_ast, global_ctx) assert devdoc == { "methods": { "foo(int128,uint256,bytes32)": { "details": "we didn't document potato, but that's ok", "params": { "bar": "a number", "baz": "also a number" }, } } }
def test_order(): node = vy_ast.parse_to_ast( "[(1 + (2 - 3)) / 4 ** 5, 6 - (7 / -(8 % 9)), 0]") node = node.body[0].value values = [i.value for i in node.get_descendants(vy_ast.Int)] assert values == [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
def test_documentation_example_output(): vyper_ast = parse_to_ast(test_code) global_ctx = GlobalContext.get_global_context(vyper_ast) userdoc, devdoc = parse_natspec(vyper_ast, global_ctx) assert userdoc == expected_userdoc assert devdoc == expected_devdoc
def test_order_reversed(): node = vy_ast.parse_to_ast( "[(1 + (2 - 3)) / 4 ** 5, 6 - (7 / -(8 % 9)), 0]") node = node.body[0].value values = [i.value for i in node.get_descendants(vy_ast.Int, reverse=True)] assert values == [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
def test_whitespace(): code = """ ''' @dev Whitespace gets cleaned up, people can use awful formatting. We don't mind! @author Mr No-linter ''' """ vyper_ast = parse_to_ast(code) global_ctx = GlobalContext.get_global_context(vyper_ast) _, devdoc = parse_natspec(vyper_ast, global_ctx) assert devdoc == { "author": "Mr No-linter", "details": "Whitespace gets cleaned up, people can use awful formatting. We don't mind!", }
def test_compare_different_node_clases(): vyper_ast = vy_ast.parse_to_ast("foo = 42") left = vyper_ast.body[0].target right = vyper_ast.body[0].value assert left != right assert not vy_ast.compare_nodes(left, right)