From a29723254d54fd6fd1c2e209e7c2e492040cb7b4 Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Sat, 26 Feb 2022 17:20:58 +0800 Subject: [PATCH 1/8] specify vyper test files --- tests/conftest.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index b1a27da7cd..72f71bacde 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,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 +210,52 @@ def _f(_addr, _salt, _initcode): return keccak(prefix + addr + salt + keccak(initcode))[12:] return _f + + +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 From 0374167209a60d9ea706e5cb7111a65e634b759a Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Sat, 26 Feb 2022 17:21:23 +0800 Subject: [PATCH 2/8] add sample vyper files --- .../constants/test_constant1_VariableDeclarationException.vy | 1 + tests/parser/syntax/constants/test_constant2_Success.vy | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/parser/syntax/constants/test_constant1_VariableDeclarationException.vy create mode 100644 tests/parser/syntax/constants/test_constant2_Success.vy 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 From bf3449471888503150c904f37f08e8f36e0793c0 Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 12:23:38 +0800 Subject: [PATCH 3/8] add fixture for Vyper files --- tests/conftest.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 72f71bacde..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 @@ -212,6 +214,30 @@ def _f(_addr, _salt, _initcode): 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) @@ -230,6 +256,7 @@ def __init__(self, name, parent): def runtest(self): try: + compile_files( [self.fspath], ("bytecode",), From 9f0f32dd9fbb9a4ce94133cd5e8b149c887ed65d Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 12:24:05 +0800 Subject: [PATCH 4/8] add example --- .../syntax/constants/test_constantGetter1_Success.vy | 5 +++++ tests/parser/syntax/test_constants.py | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/parser/syntax/constants/test_constantGetter1_Success.vy 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/test_constants.py b/tests/parser/syntax/test_constants.py index 68fca2d8df..265517dccf 100644 --- a/tests/parser/syntax/test_constants.py +++ b/tests/parser/syntax/test_constants.py @@ -201,3 +201,10 @@ 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"], indirect=True +) +def test_constant_success_2(vyper_contract): + assert vyper_contract.foo() == 123 From 3ef9776ed8e2700b8fb655fcb30690e3848dd9cb Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 15:19:35 +0800 Subject: [PATCH 5/8] add multiple contracts parametrization example --- .../syntax/constants/test_constantGetter2_Success.vy | 5 +++++ tests/parser/syntax/test_constants.py | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/parser/syntax/constants/test_constantGetter2_Success.vy 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 265517dccf..27cb7fe45a 100644 --- a/tests/parser/syntax/test_constants.py +++ b/tests/parser/syntax/test_constants.py @@ -204,7 +204,12 @@ def test_constant_success(good_code): @pytest.mark.parametrize( - "vyper_contract", ["constants/test_constantGetter1_Success.vy"], indirect=True + "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 From 4578ffd55adbca23199aab3cdc25763e6b438592 Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 16:07:41 +0800 Subject: [PATCH 6/8] move vyper pytest classes to separate file --- tests/conftest.py | 48 +----------------------------------------- tests/vyper_pytest.py | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 47 deletions(-) create mode 100644 tests/vyper_pytest.py diff --git a/tests/conftest.py b/tests/conftest.py index 18a73ee952..18c71ae4b2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,12 +11,11 @@ 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 +from .vyper_pytest import VyperFile # Import the base_conftest fixtures pytest_plugins = ["tests.base_conftest", "tests.fixtures.memorymock"] @@ -241,48 +240,3 @@ def vyper_contract(request): 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/vyper_pytest.py b/tests/vyper_pytest.py new file mode 100644 index 0000000000..f7992341ac --- /dev/null +++ b/tests/vyper_pytest.py @@ -0,0 +1,49 @@ +import pytest + +from vyper.cli.vyper_compile import compile_files +from vyper.exceptions import VyperException + + +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 From 3578b9f7213f63f629788d1643f19e6347ddec68 Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 16:15:01 +0800 Subject: [PATCH 7/8] Revert "move vyper pytest classes to separate file" This reverts commit 4578ffd55adbca23199aab3cdc25763e6b438592. --- tests/conftest.py | 48 +++++++++++++++++++++++++++++++++++++++++- tests/vyper_pytest.py | 49 ------------------------------------------- 2 files changed, 47 insertions(+), 50 deletions(-) delete mode 100644 tests/vyper_pytest.py diff --git a/tests/conftest.py b/tests/conftest.py index 18c71ae4b2..18a73ee952 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,11 +11,12 @@ 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 -from .vyper_pytest import VyperFile # Import the base_conftest fixtures pytest_plugins = ["tests.base_conftest", "tests.fixtures.memorymock"] @@ -240,3 +241,48 @@ def vyper_contract(request): 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/vyper_pytest.py b/tests/vyper_pytest.py deleted file mode 100644 index f7992341ac..0000000000 --- a/tests/vyper_pytest.py +++ /dev/null @@ -1,49 +0,0 @@ -import pytest - -from vyper.cli.vyper_compile import compile_files -from vyper.exceptions import VyperException - - -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 From 68a2fd31a2fe965a4ce444487cef9e22f75d939d Mon Sep 17 00:00:00 2001 From: Gary Tse Date: Mon, 28 Feb 2022 16:35:39 +0800 Subject: [PATCH 8/8] exclude vyper files from pytest collection for memorymock --- tests/fixtures/memorymock.py | 9 +++++++++ 1 file changed, 9 insertions(+) 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]