diff --git a/tests/conftest.py b/tests/conftest.py index b1a27da7cd..18a73ee952 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ import logging +import os +import pathlib from functools import wraps import pytest @@ -9,7 +11,9 @@ from web3.providers.eth_tester import EthereumTesterProvider from vyper import compiler +from vyper.cli.vyper_compile import compile_files from vyper.codegen.lll_node import LLLnode +from vyper.exceptions import VyperException from vyper.lll import compile_lll, optimizer from .base_conftest import VyperContract, _get_contract, zero_gas_price_strategy @@ -208,3 +212,77 @@ def _f(_addr, _salt, _initcode): return keccak(prefix + addr + salt + keccak(initcode))[12:] return _f + + +@pytest.fixture +def vyper_contract(request): + + # Get the absolute path of the Vyper test file + caller_directory = os.path.split(request.fspath)[0] + contract_file_path = pathlib.Path(os.path.join(caller_directory, request.param)) + + with contract_file_path.open() as fh: + # trailing newline fixes python parsing bug when source ends in a comment + # https://bugs.python.org/issue35107 + source_code = fh.read() + "\n" + + custom_genesis = PyEVMBackend._generate_genesis_params(overrides={"gas_limit": 4500000}) + custom_genesis["base_fee_per_gas"] = 0 + backend = PyEVMBackend(genesis_parameters=custom_genesis) + tester = EthereumTester(backend=backend) + w3 = Web3(EthereumTesterProvider(tester)) + w3.eth.set_gas_price_strategy(zero_gas_price_strategy) + + contract = _get_contract(w3, source_code, "no_optimize") + + return contract + + +def pytest_collect_file(parent, path): + if path.ext == ".vy" and path.basename.startswith("test"): + return VyperFile.from_parent(parent, fspath=path) + + +class VyperFile(pytest.File): + def collect(self): + filepath = str(self.fspath) + yield VyperTestItem.from_parent(self, name=filepath) + + +class VyperTestItem(pytest.Item): + def __init__(self, name, parent): + super().__init__(name, parent) + self.test_condition = self.name[:-3].split("_")[-1] + + def runtest(self): + try: + + compile_files( + [self.fspath], + ("bytecode",), + ) + self.test_result = "Success" + + except VyperException as v: + self.test_result = v.__class__.__name__ + + except Exception: + self.test_result = "Fail" + + if self.test_condition != self.test_result: + raise VyperTestException(self, self.name) + + def repr_failure(self, excinfo): + if isinstance(excinfo.value, VyperTestException): + return ( + f"Test failed : {self.name}\n" + f"Expected: {self.test_condition}\n" + f"Actual: {self.test_result}\n" + ) + + def reportinfo(self): + return self.fspath, 0, f"Vyper test file: {self.name}" + + +class VyperTestException(Exception): + pass diff --git a/tests/fixtures/memorymock.py b/tests/fixtures/memorymock.py index e5143a9fc2..b2195514f2 100644 --- a/tests/fixtures/memorymock.py +++ b/tests/fixtures/memorymock.py @@ -26,6 +26,15 @@ def pytest_addoption(parser): parser.addoption("--memorymock", action="store_true", help="Run tests with mock allocated vars") +def pytest_ignore_collect(path, config): + if config.getoption("memorymock"): + # Ignore Vyper test files. Otherwise, execnet will throw an error. + # Example of error: https://gist.github.com/khamidou/6b7e8702f8fc0e8dd251 + if path.ext == ".vy" and path.basename.startswith("test"): + return True + return False + + def pytest_generate_tests(metafunc): if "memory_mocker" in metafunc.fixturenames: params = range(1, 11, 2) if metafunc.config.getoption("memorymock") else [False] diff --git a/tests/parser/syntax/constants/test_constant1_VariableDeclarationException.vy b/tests/parser/syntax/constants/test_constant1_VariableDeclarationException.vy new file mode 100644 index 0000000000..c4b8ea4444 --- /dev/null +++ b/tests/parser/syntax/constants/test_constant1_VariableDeclarationException.vy @@ -0,0 +1 @@ +VAL: constant(uint256) diff --git a/tests/parser/syntax/constants/test_constant2_Success.vy b/tests/parser/syntax/constants/test_constant2_Success.vy new file mode 100644 index 0000000000..3da58e7a76 --- /dev/null +++ b/tests/parser/syntax/constants/test_constant2_Success.vy @@ -0,0 +1 @@ +VAL: constant(uint256) = 123 diff --git a/tests/parser/syntax/constants/test_constantGetter1_Success.vy b/tests/parser/syntax/constants/test_constantGetter1_Success.vy new file mode 100644 index 0000000000..9978cfb744 --- /dev/null +++ b/tests/parser/syntax/constants/test_constantGetter1_Success.vy @@ -0,0 +1,5 @@ +VAL: constant(uint256) = 123 + +@external +def foo() -> uint256: + return VAL diff --git a/tests/parser/syntax/constants/test_constantGetter2_Success.vy b/tests/parser/syntax/constants/test_constantGetter2_Success.vy new file mode 100644 index 0000000000..bfac6638b4 --- /dev/null +++ b/tests/parser/syntax/constants/test_constantGetter2_Success.vy @@ -0,0 +1,5 @@ +VAL: constant(int128) = 123 + +@external +def foo() -> int128: + return VAL diff --git a/tests/parser/syntax/test_constants.py b/tests/parser/syntax/test_constants.py index 68fca2d8df..27cb7fe45a 100644 --- a/tests/parser/syntax/test_constants.py +++ b/tests/parser/syntax/test_constants.py @@ -201,3 +201,15 @@ def deposit(deposit_input: Bytes[2048]): @pytest.mark.parametrize("good_code", valid_list) def test_constant_success(good_code): assert compiler.compile_code(good_code) is not None + + +@pytest.mark.parametrize( + "vyper_contract", + [ + "constants/test_constantGetter1_Success.vy", + "constants/test_constantGetter2_Success.vy", + ], + indirect=True, +) +def test_constant_success_2(vyper_contract): + assert vyper_contract.foo() == 123