From 1c18e15b1c8358de870650d2bbc7c0149dfb4b8c Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Fri, 5 Jan 2024 09:43:00 -0600 Subject: [PATCH] fix: ct collide from del ct --- src/ape/managers/compilers.py | 20 ++++++++++-------- tests/functional/conftest.py | 16 ++++++++++++--- tests/functional/test_project.py | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/ape/managers/compilers.py b/src/ape/managers/compilers.py index 21be1bad6f..091eee371f 100644 --- a/src/ape/managers/compilers.py +++ b/src/ape/managers/compilers.py @@ -115,14 +115,18 @@ def compile( cached_manifest = self.project_manager.local_project.cached_manifest # Load past compiled contracts for verifying type-collision and other things. - already_compiled_contracts = ( - (cached_manifest.contract_types or {}) if cached_manifest else {} - ) - already_compiled_paths = [ - contracts_folder / x.source_id - for x in already_compiled_contracts.values() - if x.source_id - ] + already_compiled_contracts: Dict[str, ContractType] = {} + already_compiled_paths: List[Path] = [] + for name, ct in ((cached_manifest.contract_types or {}) if cached_manifest else {}).items(): + if not ct.source_id: + continue + + _file = contracts_folder / ct.source_id + if not _file.is_file(): + continue + + already_compiled_contracts[name] = ct + already_compiled_paths.append(_file) exclusions = self.config_manager.get_config("compile").exclude for extension in extensions: diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 7f02e90310..6e44fc8b3a 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -676,9 +676,19 @@ def mock_compile(paths, base_path=None): if path.suffix == mock.ext: name = path.stem code = HexBytes(123).hex() - contract_type = ContractType( - contractName=name, abi=[], deploymentBytecode=code, sourceId=path.name - ) + data = { + "contractName": name, + "abi": [], + "deploymentBytecode": code, + "sourceId": path.name, + } + + # Check for mocked overrides + overrides = mock.overrides + if isinstance(overrides, dict): + data = {**data, **overrides} + + contract_type = ContractType.model_validate(data) result.append(contract_type) return result diff --git a/tests/functional/test_project.py b/tests/functional/test_project.py index a4505067bc..10fa58a24e 100644 --- a/tests/functional/test_project.py +++ b/tests/functional/test_project.py @@ -499,6 +499,41 @@ def test_load_contracts(project_with_contract): assert contracts == project_with_contract.contracts +def test_load_contracts_after_deleting_same_named_contract(config, compilers, mock_compiler): + """ + Tests against a scenario where you: + + 1. Add and compile a contract + 2. Delete that contract + 3. Add a new contract with same name somewhere else + + Test such that we are able to compile successfully and not get a misleading + collision error from deleted files. + """ + + with tempfile.TemporaryDirectory() as temp_dir: + path = Path(temp_dir) + contracts = path / "contracts" + contracts.mkdir() + init_contract = contracts / "foo.__mock__" + init_contract.write_text("LALA") + with config.using_project(path) as proj: + compilers.registered_compilers[".__mock__"] = mock_compiler + result = proj.load_contracts() + assert "foo" in result + + # Delete file + init_contract.unlink() + + # Create new contract that yields same name as deleted one. + new_contract = contracts / "bar.__mock__" + new_contract.write_text("BAZ") + mock_compiler.overrides = {"contractName": "foo"} + + result = proj.load_contracts() + assert "foo" in result + + def test_add_compiler_data(project_with_dependency_config): # NOTE: Using different project than default to lessen # chance of race-conditions from multi-process test runners.