initial tests

pull/2099/head
alpharush 1 year ago
parent baa3c980c2
commit ae45f461e3
  1. 23
      slither/core/declarations/function.py
  2. 20
      tests/conftest.py
  3. 85
      tests/unit/core/test_function_declaration.py
  4. 0
      tests/unit/slithir/vyper/__init__.py
  5. 65
      tests/unit/slithir/vyper/test_ir_generation.py

@ -106,7 +106,8 @@ def _filter_state_variables_written(expressions: List["Expression"]):
ret.append(expression.expression_left)
return ret
#TODO replace
# TODO replace
class FunctionLanguage(Enum):
Solidity = 0
Yul = 1
@ -238,7 +239,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
if self._name == "" and self._function_type == FunctionType.CONSTRUCTOR:
return "constructor"
if self._function_type == FunctionType.FALLBACK:
if self._name == "" and self._function_type == FunctionType.FALLBACK:
return "fallback"
if self._function_type == FunctionType.RECEIVE:
return "receive"
@ -985,14 +986,15 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
(str, list(str), list(str)): Function signature as
(name, list parameters type, list return values type)
"""
if self._signature is None:
signature = (
self.name,
[str(x.type) for x in self.parameters],
[str(x.type) for x in self.returns],
)
self._signature = signature
return self._signature
# FIXME memoizing this function is not working properly for vyper
# if self._signature is None:
return (
self.name,
[str(x.type) for x in self.parameters],
[str(x.type) for x in self.returns],
)
# self._signature = signature
# return self._signature
@property
def signature_str(self) -> str:
@ -1758,7 +1760,6 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def generate_slithir_and_analyze(self) -> None:
print("generate_slithir_and_analyze")
print(self.nodes)
for node in self.nodes:
node.slithir_generation()

@ -77,3 +77,23 @@ def slither_from_solidity_source(solc_binary_path):
Path(fname).unlink()
return inner
@pytest.fixture
def slither_from_vyper_source():
@contextmanager
def inner(source_code: str):
"""Yields a Slither instance using source_code string.
Creates a temporary file and compiles with vyper.
"""
fname = ""
try:
with tempfile.NamedTemporaryFile(mode="w", suffix=".vy", delete=False) as f:
fname = f.name
f.write(source_code)
yield Slither(fname)
finally:
Path(fname).unlink()
return inner

@ -9,6 +9,7 @@ from pathlib import Path
from slither import Slither
from slither.core.declarations.function import FunctionType
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.mapping_type import MappingType
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data"
FUNC_DELC_TEST_ROOT = Path(TEST_DATA_DIR, "function_declaration")
@ -302,3 +303,87 @@ def test_public_variable(solc_binary_path) -> None:
assert var.signature_str == "info() returns(bytes32)"
assert var.visibility == "public"
assert var.type == ElementaryType("bytes32")
def test_vyper_functions(slither_from_vyper_source) -> None:
with slither_from_vyper_source(
"""
balances: public(HashMap[address, uint256])
allowances: HashMap[address, HashMap[address, uint256]]
@pure
@internal
def add(x: int128, y: int128) -> int128:
return x + y
@external
def __init__():
pass
@external
def withdraw():
raw_call(msg.sender, b"", value= self.balances[msg.sender])
@external
@nonreentrant("lock")
def withdraw_locked():
raw_call(msg.sender, b"", value= self.balances[msg.sender])
@payable
@external
def __default__():
pass
"""
) as sl:
contract = sl.contracts[0]
functions = contract.available_functions_as_dict()
f = functions["add(int128,int128)"]
assert f.function_type == FunctionType.NORMAL
assert f.visibility == "internal"
assert not f.payable
assert f.view is False
assert f.pure is True
assert f.parameters[0].name == "x"
assert f.parameters[0].type == ElementaryType("int128")
assert f.parameters[1].name == "y"
assert f.parameters[1].type == ElementaryType("int128")
assert f.return_type[0] == ElementaryType("int128")
f = functions["__init__()"]
assert f.function_type == FunctionType.CONSTRUCTOR
assert f.visibility == "external"
assert not f.payable
assert not f.view
assert not f.pure
f = functions["__default__()"]
assert f.function_type == FunctionType.FALLBACK
assert f.visibility == "external"
assert f.payable
assert not f.view
assert not f.pure
f = functions["withdraw()"]
assert f.function_type == FunctionType.NORMAL
assert f.visibility == "external"
assert not f.payable
assert not f.view
assert not f.pure
assert f.can_send_eth()
assert f.can_reenter()
# f = functions["withdraw_locked()"]
# assert not f.can_reenter()
var = contract.get_state_variable_from_name("balances")
assert var
assert var.solidity_signature == "balances(address)"
assert var.signature_str == "balances(address) returns(uint256)"
assert var.visibility == "public"
assert var.type == MappingType(ElementaryType("address"), ElementaryType("uint256"))
var = contract.get_state_variable_from_name("allowances")
assert var
assert var.solidity_signature == "allowances(address,address)"
assert var.signature_str == "allowances(address,address) returns(uint256)"
assert var.visibility == "internal"
assert var.type == MappingType(
ElementaryType("address"),
MappingType(ElementaryType("address"), ElementaryType("uint256")),
)

@ -0,0 +1,65 @@
# # pylint: disable=too-many-lines
import pathlib
from argparse import ArgumentTypeError
from collections import defaultdict
from inspect import getsourcefile
from typing import Union, List, Dict, Callable
import pytest
from slither import Slither
from slither.core.cfg.node import Node, NodeType
from slither.core.declarations import Function, Contract
from slither.core.solidity_types import ArrayType
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import (
OperationWithLValue,
Phi,
Assignment,
HighLevelCall,
Return,
Operation,
Binary,
BinaryType,
InternalCall,
Index,
InitArray,
)
from slither.slithir.utils.ssa import is_used_later
from slither.slithir.variables import (
Constant,
ReferenceVariable,
LocalIRVariable,
StateIRVariable,
TemporaryVariableSSA,
)
def test_interface_conversion_and_call_resolution(slither_from_vyper_source):
with slither_from_vyper_source(
"""
interface Test:
def foo() -> (int128, uint256): nonpayable
@internal
def foo() -> (int128, int128):
return 2, 3
@external
def bar():
a: int128 = 0
b: int128 = 0
(a, b) = self.foo()
x: address = 0x0000000000000000000000000000000000000000
c: uint256 = 0
a, c = Test(x).foo()
"""
) as sl:
interface = next(iter(x for x in sl.contracts if x.is_interface))
contract = next(iter(x for x in sl.contracts if not x.is_interface))
func = contract.get_function_from_signature("bar()")
(contract, function) = func.high_level_calls[0]
assert contract == interface
assert function.signature_str == "foo() returns(int128,uint256)"
Loading…
Cancel
Save