diff --git a/src/ape/api/compiler.py b/src/ape/api/compiler.py index 765f335a3b..71d6a6fa0f 100644 --- a/src/ape/api/compiler.py +++ b/src/ape/api/compiler.py @@ -193,7 +193,10 @@ def _create_contract_from_call( if "address" not in data: return None, calldata - addr = data["address"] + # NOTE: Handling when providers give us odd address values. + raw_addr = HexBytes(data["address"]).hex().replace("0x", "") + zeroes = max(40 - len(raw_addr), 0) * "0" + addr = f"0x{zeroes}{raw_addr}" try: address = self.provider.network.ecosystem.decode_address(addr) diff --git a/src/ape/api/providers.py b/src/ape/api/providers.py index 27a361a9a9..14ce3eff48 100644 --- a/src/ape/api/providers.py +++ b/src/ape/api/providers.py @@ -56,6 +56,7 @@ ContractLog, LogFilter, SnapshotID, + SourceTraceback, TraceFrame, ) from ape.utils import ( @@ -702,16 +703,9 @@ def _increment_call_func_coverage_hit_count(self, txn: TransactionAPI): ): return - cov_data = self._test_runner.coverage_tracker.data - if not cov_data: - return - - contract_type = self.chain_manager.contracts.get(txn.receiver) - if not contract_type: - return - - contract_src = self.project_manager._create_contract_source(contract_type) - if not contract_src: + if not (contract_type := self.chain_manager.contracts.get(txn.receiver)) or not ( + contract_src := self.project_manager._create_contract_source(contract_type) + ): return method_id = txn.data[:4] @@ -1571,8 +1565,7 @@ def get_virtual_machine_error(self, exception: Exception, **kwargs) -> VirtualMa if not isinstance(err_data, dict): return VirtualMachineError(base_err=exception, **kwargs) - err_msg = err_data.get("message") - if not err_msg: + if not (err_msg := err_data.get("message")): return VirtualMachineError(base_err=exception, **kwargs) if txn is not None and "nonce too low" in str(err_msg): @@ -1593,9 +1586,14 @@ def _handle_execution_reverted( txn: Optional[TransactionAPI] = None, trace: Optional[Iterator[TraceFrame]] = None, contract_address: Optional[AddressType] = None, + source_traceback: Optional[SourceTraceback] = None, ) -> ContractLogicError: message = str(exception).split(":")[-1].strip() - params: Dict = {"trace": trace, "contract_address": contract_address} + params: Dict = { + "trace": trace, + "contract_address": contract_address, + "source_traceback": source_traceback, + } no_reason = message == "execution reverted" if isinstance(exception, Web3ContractLogicError) and no_reason: diff --git a/src/ape/exceptions.py b/src/ape/exceptions.py index b78d4ccf2e..75fb039338 100644 --- a/src/ape/exceptions.py +++ b/src/ape/exceptions.py @@ -2,8 +2,6 @@ import tempfile import time import traceback -from collections import deque -from functools import cached_property from inspect import getframeinfo, stack from pathlib import Path from types import CodeType, TracebackType @@ -11,7 +9,6 @@ import click from eth_utils import humanize_hash -from ethpm_types import ContractType from ethpm_types.abi import ConstructorABI, ErrorABI, MethodABI from rich import print as rich_print @@ -180,12 +177,10 @@ def _set_tb(self): if not self.source_traceback and self.txn: self.source_traceback = _get_ape_traceback(self.txn) - src_tb = self.source_traceback - if src_tb is not None and self.txn is not None: + if (src_tb := self.source_traceback) and self.txn is not None: # Create a custom Pythonic traceback using lines from the sources # found from analyzing the trace of the transaction. - py_tb = _get_custom_python_traceback(self, self.txn, src_tb) - if py_tb: + if py_tb := _get_custom_python_traceback(self, self.txn, src_tb): self.__traceback__ = py_tb @@ -213,12 +208,6 @@ def __init__( self.txn = txn self.trace = trace self.contract_address = contract_address - if revert_message is None: - try: - # Attempt to use dev message as main exception message. - revert_message = self.dev_message - except Exception: - pass super().__init__( base_err=base_err, @@ -229,11 +218,18 @@ def __init__( txn=txn, ) + if revert_message is None and source_traceback is not None and (dev := self.dev_message): + try: + # Attempt to use dev message as main exception message. + self.message = dev + except Exception: + pass + @property def revert_message(self): return self.message - @cached_property + @property def dev_message(self) -> Optional[str]: """ The dev-string message of the exception. @@ -242,109 +238,7 @@ def dev_message(self) -> Optional[str]: ``ValueError``: When unable to get dev message. """ - trace = self._get_trace() - if len(trace) == 0: - raise ValueError("Missing trace.") - - if address := self.address: - try: - contract_type = trace[-1].chain_manager.contracts[address] - except Exception as err: - raise ValueError( - f"Could not fetch contract at {address} to check dev message." - ) from err - - else: - raise ValueError("Could not fetch contract information to check dev message.") - - if contract_type.pcmap is None: - raise ValueError("Compiler does not support source code mapping.") - - pc = None - pcmap = contract_type.pcmap.parse() - - # To find a suitable line for inspecting dev messages, we must start at the revert and work - # our way backwards. If the last frame's PC is in the PC map, the offending line is very - # likely a 'raise' statement. - if trace[-1].pc in pcmap: - pc = trace[-1].pc - - # Otherwise we must traverse the trace backwards until we find our first suitable candidate. - else: - last_depth = 1 - while len(trace) > 0: - frame = trace.pop() - if frame.depth > last_depth: - # Call was made, get the new PCMap. - contract_type = self._find_next_contract(trace) - if not contract_type.pcmap: - raise ValueError("Compiler does not support source code mapping.") - - pcmap = contract_type.pcmap.parse() - last_depth += 1 - - if frame.pc in pcmap: - pc = frame.pc - break - - # We were unable to find a suitable PC that matched the compiler's map. - if pc is None: - return None - - offending_source = pcmap[pc] - if offending_source is None: - return None - - dev_messages = contract_type.dev_messages or {} - if offending_source.line_start is None: - # Check for a `dev` field in PCMap. - return None if offending_source.dev is None else offending_source.dev - - elif offending_source.line_start in dev_messages: - return dev_messages[offending_source.line_start] - - elif offending_source.dev is not None: - return offending_source.dev - - # Dev message is neither found from the compiler or from a dev-comment. - return None - - def _get_trace(self) -> deque: - trace = None - if self.trace is None and self.txn is not None: - try: - trace = deque(self.txn.trace) - except APINotImplementedError as err: - raise ValueError( - "Cannot check dev message; provider must support transaction tracing." - ) from err - - except (ProviderError, SignatureError) as err: - raise ValueError("Cannot fetch transaction trace.") from err - - elif self.trace is not None: - trace = deque(self.trace) - - if not trace: - raise ValueError("Cannot fetch transaction trace.") - - return trace - - def _find_next_contract(self, trace: deque) -> ContractType: - msg = "Could not fetch contract at '{address}' to check dev message." - idx = len(trace) - 1 - while idx >= 0: - frame = trace[idx] - if frame.contract_address: - ct = frame.chain_manager.contracts.get(frame.contract_address) - if not ct: - raise ValueError(msg.format(address=frame.contract_address)) - - return ct - - idx -= 1 - - raise ValueError(msg.format(address=frame.contract_address)) + return self.source_traceback.revert_type if self.source_traceback else None @classmethod def from_error(cls, err: Exception): diff --git a/src/ape/types/trace.py b/src/ape/types/trace.py index 32a50d2eb0..b1c4a5b63b 100644 --- a/src/ape/types/trace.py +++ b/src/ape/types/trace.py @@ -1,6 +1,6 @@ -from itertools import tee +from itertools import chain, tee from pathlib import Path -from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Set +from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Set, Union from ethpm_types import ASTNode, BaseModel, ContractType, HexBytes from ethpm_types.ast import SourceLocation @@ -489,17 +489,17 @@ class SourceTraceback(BaseModel): __root__: List[ControlFlow] @classmethod - def create(cls, contract_type: ContractType, trace: Iterator[TraceFrame], data: HexBytes): - source_id = contract_type.source_id - if not source_id: + def create( + cls, + contract_type: ContractType, + trace: Iterator[TraceFrame], + data: Union[HexBytes, str], + ): + trace, second_trace = tee(trace) + if not second_trace or not (accessor := next(second_trace, None)): return cls.parse_obj([]) - trace, second_trace = tee(trace) - if second_trace: - accessor = next(second_trace, None) - if not accessor: - return cls.parse_obj([]) - else: + if not (source_id := contract_type.source_id): return cls.parse_obj([]) ext = f".{source_id.split('.')[-1]}" @@ -508,7 +508,7 @@ def create(cls, contract_type: ContractType, trace: Iterator[TraceFrame], data: compiler = accessor.compiler_manager.registered_compilers[ext] try: - return compiler.trace_source(contract_type, trace, data) + return compiler.trace_source(contract_type, trace, HexBytes(data)) except NotImplementedError: return cls.parse_obj([]) @@ -533,10 +533,25 @@ def __getitem__(self, idx: int) -> ControlFlow: def __setitem__(self, key, value): return self.__root__.__setitem__(key, value) + @property + def revert_type(self) -> Optional[str]: + """ + The revert type, such as a builtin-error code or a user dev-message, + if there is one. + """ + + return self.statements[-1].type if self.statements[-1].type != "source" else None + def append(self, __object) -> None: + """ + Append the given control flow to this one. + """ self.__root__.append(__object) def extend(self, __iterable) -> None: + """ + Append all the control flows from the given traceback to this one. + """ if not isinstance(__iterable, SourceTraceback): raise TypeError("Can only extend another traceback object.") @@ -544,13 +559,37 @@ def extend(self, __iterable) -> None: @property def last(self) -> Optional[ControlFlow]: + """ + The last control flow in the traceback, if there is one. + """ return self.__root__[-1] if len(self.__root__) else None @property def execution(self) -> List[ControlFlow]: + """ + All the control flows in order. Each set of statements in + a control flow is separated by a jump. + """ return list(self.__root__) + @property + def statements(self) -> List[Statement]: + """ + All statements from each control flow. + """ + return list(chain(*[x.statements for x in self.__root__])) + + @property + def source_statements(self) -> List[SourceStatement]: + """ + All source statements from each control flow. + """ + return list(chain(*[x.source_statements for x in self.__root__])) + def format(self) -> str: + """ + Get a formatted traceback string for displaying to users. + """ if not len(self.__root__): # No calls. return "" @@ -566,6 +605,10 @@ def format(self) -> str: continue last_depth = control_flow.depth + content_str = control_flow.format() + if not content_str.strip(): + continue + segment = f"{indent}{control_flow.source_header}\n{control_flow.format()}" # Try to include next statement for display purposes. @@ -660,6 +703,20 @@ def add_builtin_jump( source_path: Optional[Path] = None, pcs: Optional[Set[int]] = None, ): + """ + A convenience method for appending a control flow that happened + from an internal compiler built-in code. See the ape-vyper plugin + for a usage example. + + Args: + name (str): The name of the compiler built-in. + _type (str): A str describing the type of check. + compiler_name (str): The name of the compiler. + full_name (Optional[str]): A full-name ID. + source_path (Optional[Path]): The source file related, if there is one. + pcs (Optional[Set[int]]): Program counter values mapping to this check. + """ + # TODO: Assess if compiler_name is needed or get rid of in v0.7. pcs = pcs or set() closure = Closure(name=name, full_name=full_name or name) depth = self.last.depth - 1 if self.last else 0 diff --git a/src/ape/utils/__init__.py b/src/ape/utils/__init__.py index 04bf3649d7..3ca3146d10 100644 --- a/src/ape/utils/__init__.py +++ b/src/ape/utils/__init__.py @@ -55,7 +55,7 @@ GeneratedDevAccount, generate_dev_accounts, ) -from ape.utils.trace import TraceStyles, parse_coverage_tables, parse_gas_table +from ape.utils.trace import USER_ASSERT_TAG, TraceStyles, parse_coverage_tables, parse_gas_table __all__ = [ "abstractmethod", @@ -108,5 +108,6 @@ "TraceStyles", "use_temp_sys_path", "USER_AGENT", + "USER_ASSERT_TAG", "ZERO_ADDRESS", ] diff --git a/src/ape/utils/trace.py b/src/ape/utils/trace.py index 9595b3fb54..239fc94069 100644 --- a/src/ape/utils/trace.py +++ b/src/ape/utils/trace.py @@ -16,6 +16,7 @@ _WRAP_THRESHOLD = 50 _INDENT = 2 +USER_ASSERT_TAG = "USER_ASSERT" class TraceStyles: diff --git a/src/ape_ethereum/transactions.py b/src/ape_ethereum/transactions.py index 63ff4d1201..2d3c70db4f 100644 --- a/src/ape_ethereum/transactions.py +++ b/src/ape_ethereum/transactions.py @@ -175,13 +175,12 @@ def method_called(self) -> Optional[MethodABI]: return self.contract_type.methods[method_id] - @property + @cached_property def source_traceback(self) -> SourceTraceback: - contract_type = self.contract_type - if not contract_type: - return SourceTraceback.parse_obj([]) + if contract_type := self.contract_type: + return SourceTraceback.create(contract_type, self.trace, HexBytes(self.data)) - return SourceTraceback.create(contract_type, self.trace, HexBytes(self.data)) + return SourceTraceback.parse_obj([]) def raise_for_status(self): if self.gas_limit is not None and self.ran_out_of_gas: @@ -192,8 +191,7 @@ def raise_for_status(self): raise TransactionError(f"Transaction '{txn_hash}' failed.", txn=self) def show_trace(self, verbose: bool = False, file: IO[str] = sys.stdout): - call_tree = self.call_tree - if not call_tree: + if not (call_tree := self.call_tree): return call_tree.enrich(use_symbol_for_tokens=True) @@ -223,8 +221,7 @@ def show_trace(self, verbose: bool = False, file: IO[str] = sys.stdout): ) def show_gas_report(self, file: IO[str] = sys.stdout): - call_tree = self.call_tree - if not call_tree: + if not (call_tree := self.call_tree): return call_tree.enrich() @@ -283,8 +280,7 @@ def decode_logs( event_abi = selectors[contract_address][selector] except KeyError: # Likely a library log - library_log = self._decode_ds_note(log) - if library_log: + if library_log := self._decode_ds_note(log): decoded_logs.append(library_log) else: decoded_logs.extend( @@ -300,8 +296,7 @@ def _decode_ds_note(self, log: Dict) -> Optional[ContractLog]: # non-zero bytes found after selector return None - contract_type = self.chain_manager.contracts.get(log["address"]) - if contract_type is None: + if not (contract_type := self.chain_manager.contracts.get(log["address"])): # contract type for {log['address']} not found return None diff --git a/src/ape_geth/provider.py b/src/ape_geth/provider.py index 7a56ff1829..227319d10d 100644 --- a/src/ape_geth/provider.py +++ b/src/ape_geth/provider.py @@ -585,20 +585,19 @@ def send_call(self, txn: TransactionAPI, **kwargs: Any) -> bytes: # NOTE: Don't pass txn_hash here, as it will fail (this is not a real txn). call_tree = self._create_call_tree_node(evm_call_tree) - receiver = txn.receiver if track_gas and show_gas and not show_trace and call_tree: # Optimization to enrich early and in_place=True. call_tree.enrich() - if track_gas and call_tree and receiver is not None and self._test_runner is not None: + if track_gas and call_tree and self._test_runner is not None and txn.receiver: # Gas report being collected, likely for showing a report # at the end of a test run. # Use `in_place=False` in case also `show_trace=True` enriched_call_tree = call_tree.enrich(in_place=False) - self._test_runner.gas_tracker.append_gas(enriched_call_tree, receiver) + self._test_runner.gas_tracker.append_gas(enriched_call_tree, txn.receiver) - if track_coverage and self._test_runner is not None and receiver: - contract_type = self.chain_manager.contracts.get(receiver) + if track_coverage and self._test_runner is not None and txn.receiver: + contract_type = self.chain_manager.contracts.get(txn.receiver) if contract_type: traceframes = (self._create_trace_frame(x) for x in frames_copy) method_id = HexBytes(txn.data) @@ -631,10 +630,17 @@ def _eth_call(self, arguments: List) -> bytes: try: result = self._make_request("eth_call", arguments) except Exception as err: - trace = (self._create_trace_frame(x) for x in self._trace_call(arguments)[1]) + trace, trace2 = tee(self._create_trace_frame(x) for x in self._trace_call(arguments)[1]) contract_address = arguments[0]["to"] + contract_type = self.chain_manager.contracts.get(contract_address) + method_id = arguments[0].get("data", "")[:10] or None + tb = ( + SourceTraceback.create(contract_type, trace, method_id) + if method_id and contract_type + else None + ) raise self.get_virtual_machine_error( - err, trace=trace, contract_address=contract_address + err, trace=trace2, contract_address=contract_address, source_traceback=tb ) from err if "error" in result: diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index a5011e71e6..af92876135 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -149,11 +149,6 @@ def vyper_fallback_container(vyper_fallback_contract_type) -> ContractContainer: return ContractContainer(contract_type=vyper_fallback_contract_type) -@pytest.fixture(scope="session") -def vyper_math_dev_check(get_contract_type) -> ContractContainer: - return ContractContainer(contract_type=get_contract_type("vyper_math_dev_checks")) - - @pytest.fixture def vyper_contract_instance( owner, vyper_contract_container, networks_connected_to_tester @@ -178,7 +173,7 @@ def reverts_contract_type(get_contract_type) -> ContractType: @pytest.fixture(scope="session") def sub_reverts_contract_type(get_contract_type) -> ContractType: - return get_contract_type("sub_reverts_contract") + return get_contract_type("sub_reverts") @pytest.fixture(scope="session") diff --git a/tests/functional/data/contracts/ethereum/local/sub_reverts.json b/tests/functional/data/contracts/ethereum/local/sub_reverts.json new file mode 100644 index 0000000000..cc55657c7e --- /dev/null +++ b/tests/functional/data/contracts/ethereum/local/sub_reverts.json @@ -0,0 +1 @@ +{"abi":[{"inputs":[{"name":"a","type":"uint256"}],"name":"revertStrings","outputs":[{"name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"ast":{"ast_type":"Module","children":[{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":1,"col_offset":21,"end_col_offset":28,"end_lineno":4,"lineno":4,"src":{"jump_code":"","length":7,"start":49}}],"classification":0,"col_offset":18,"end_col_offset":28,"end_lineno":4,"lineno":4,"src":{"jump_code":"","length":10,"start":46}}],"classification":1,"col_offset":18,"end_col_offset":28,"end_lineno":4,"lineno":4,"src":{"jump_code":"","length":10,"start":46}},{"ast_type":"Assert","children":[{"ast_type":"Compare","children":[{"ast_type":"Name","children":[],"classification":1,"col_offset":11,"end_col_offset":12,"end_lineno":5,"lineno":5,"src":{"jump_code":"","length":1,"start":78}},{"ast_type":"NotEq","children":[],"classification":0,"col_offset":11,"end_col_offset":17,"end_lineno":5,"lineno":5,"src":{"jump_code":"","length":6,"start":78}},{"ast_type":"Int","children":[],"classification":0,"col_offset":16,"end_col_offset":17,"end_lineno":5,"lineno":5,"src":{"jump_code":"","length":1,"start":83}}],"classification":0,"col_offset":11,"end_col_offset":17,"end_lineno":5,"lineno":5,"src":{"jump_code":"","length":6,"start":78}}],"classification":0,"col_offset":4,"end_col_offset":17,"end_lineno":5,"lineno":5,"src":{"jump_code":"","length":13,"start":71}},{"ast_type":"Return","children":[{"ast_type":"NameConstant","children":[],"classification":0,"col_offset":11,"end_col_offset":15,"end_lineno":6,"lineno":6,"src":{"jump_code":"","length":4,"start":113}}],"classification":0,"col_offset":4,"end_col_offset":15,"end_lineno":6,"lineno":6,"src":{"jump_code":"","length":11,"start":106}},{"ast_type":"Name","children":[],"classification":1,"col_offset":1,"end_col_offset":9,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":8,"start":19}},{"ast_type":"Name","children":[],"classification":1,"col_offset":33,"end_col_offset":37,"end_lineno":4,"lineno":4,"src":{"jump_code":"","length":4,"start":61}}],"classification":1,"col_offset":0,"end_col_offset":15,"end_lineno":6,"lineno":4,"name":"revertStrings","src":{"jump_code":"","length":89,"start":28}}],"classification":0,"col_offset":0,"end_col_offset":15,"end_lineno":6,"lineno":1,"name":"revert_strings_v037.vy","src":{"jump_code":"","length":117}},"contractName":"revert_strings_v037","deploymentBytecode":{"bytecode":"0x61005761000f6000396100576000f36003361161000c5761003f565b60003560e01c346100455763d8046e7d811861003d5760243610610045576004351561004557600160405260206040f35b505b60006000fd5b600080fda165767970657283000307000b"},"dev_messages":{"5":"dev: sub-zero"},"devdoc":{},"pcmap":{"11":{"dev":"dev: Fallback not defined","location":null},"20":{"dev":"dev: USER_ASSERT","location":null},"43":{"location":[5,11,5,12]},"45":{"location":[5,11,5,17]},"46":{"location":[5,11,5,17]},"47":{"location":[5,4,5,17]},"50":{"dev":"dev: USER_ASSERT","location":[5,4,5,17]},"51":{"location":[6,11,6,15]}},"runtimeBytecode":{"bytecode":"0x6003361161000c5761003f565b60003560e01c346100455763d8046e7d811861003d5760243610610045576004351561004557600160405260206040f35b505b60006000fd5b600080fda165767970657283000307000b"},"sourceId":"revert_strings_v037.vy","sourcemap":"-1:-1:0:-;;;;:::-;;:::-;:::-;;;;;;;:::-;;;;;:::-;;;;;:::-;78:1;:6;;71:13;:::-;113:4;-1:-1;;;;;:::-;;:::-;;;;:::-;;;","userdoc":{}} diff --git a/tests/functional/data/contracts/ethereum/local/sub_reverts_contract.json b/tests/functional/data/contracts/ethereum/local/sub_reverts_contract.json deleted file mode 100644 index c9903e5f13..0000000000 --- a/tests/functional/data/contracts/ethereum/local/sub_reverts_contract.json +++ /dev/null @@ -1 +0,0 @@ -{"abi":[{"inputs":[{"name":"a","type":"uint256"}],"name":"revertStrings","outputs":[{"name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"ast":{"ast_type":"Module","children":[{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":21,"end_col_offset":28,"end_lineno":2,"lineno":2,"src":{"contract_id":2,"jump_code":"","length":7,"start":31}}],"classification":0,"col_offset":18,"end_col_offset":28,"end_lineno":2,"lineno":2,"src":{"contract_id":2,"jump_code":"","length":10,"start":28}}],"classification":0,"col_offset":18,"end_col_offset":28,"end_lineno":2,"lineno":2,"src":{"contract_id":2,"jump_code":"","length":10,"start":28}},{"ast_type":"Assert","children":[{"ast_type":"Compare","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":11,"end_col_offset":12,"end_lineno":3,"lineno":3,"src":{"contract_id":2,"jump_code":"","length":1,"start":60}},{"ast_type":"NotEq","children":[],"classification":0,"col_offset":11,"end_col_offset":17,"end_lineno":3,"lineno":3,"src":{"contract_id":2,"jump_code":"","length":6,"start":60}},{"ast_type":"Int","children":[],"classification":0,"col_offset":16,"end_col_offset":17,"end_lineno":3,"lineno":3,"src":{"contract_id":2,"jump_code":"","length":1,"start":65}}],"classification":0,"col_offset":11,"end_col_offset":17,"end_lineno":3,"lineno":3,"src":{"contract_id":2,"jump_code":"","length":6,"start":60}}],"classification":0,"col_offset":4,"end_col_offset":17,"end_lineno":3,"lineno":3,"src":{"contract_id":2,"jump_code":"","length":13,"start":53}},{"ast_type":"Return","children":[{"ast_type":"NameConstant","children":[],"classification":0,"col_offset":11,"end_col_offset":15,"end_lineno":4,"lineno":4,"src":{"contract_id":2,"jump_code":"","length":4,"start":95}}],"classification":0,"col_offset":4,"end_col_offset":15,"end_lineno":4,"lineno":4,"src":{"contract_id":2,"jump_code":"","length":11,"start":88}},{"ast_type":"Name","children":[],"classification":0,"col_offset":1,"end_col_offset":9,"end_lineno":1,"lineno":1,"src":{"contract_id":2,"jump_code":"","length":8,"start":1}},{"ast_type":"Name","children":[],"classification":0,"col_offset":33,"end_col_offset":37,"end_lineno":2,"lineno":2,"src":{"contract_id":2,"jump_code":"","length":4,"start":43}}],"classification":0,"col_offset":0,"end_col_offset":15,"end_lineno":4,"lineno":2,"src":{"contract_id":2,"jump_code":"","length":89,"start":10}}],"classification":0,"col_offset":0,"end_col_offset":15,"end_lineno":4,"lineno":1,"src":{"contract_id":2,"jump_code":"","length":99}},"contractName":"SubRevertsVy","deploymentBytecode":{"bytecode":"0x61005761000f6000396100576000f36003361161000c5761003f565b60003560e01c346100455763d8046e7d811861003d5760243610610045576004351561004557600160405260206040f35b505b60006000fd5b600080fda165767970657283000307000b"},"dev_messages":{"3":"dev: sub-zero"},"devdoc":{},"pcmap":{"23":{"dev":"dev: Cannot send ether to non-payable function","location":null},"43":{"location":[3,11,3,12]},"45":{"location":[3,11,3,17]},"46":{"location":[3,11,3,17]},"47":{"location":[3,4,3,17]},"50":{"location":[3,4,3,17]},"51":{"location":[4,11,4,15]}},"runtimeBytecode":{"bytecode":"0x6003361161000c5761003f565b60003560e01c346100455763d8046e7d811861003d5760243610610045576004351561004557600160405260206040f35b505b60006000fd5b600080fda165767970657283000307000b"},"sourceId":"SubRevertsVy.vy","sourcemap":"-1:-1:2:-;;;;:::-;;:::-;:::-;;;;;;;:::-;;;;;:::-;;;;;:::-;60:1;:6;;53:13;:::-;95:4;-1:-1;;;;;:::-;;:::-;;;;:::-;;;","userdoc":{}} diff --git a/tests/functional/data/contracts/ethereum/local/vyper_math_dev_checks.json b/tests/functional/data/contracts/ethereum/local/vyper_math_dev_checks.json deleted file mode 100644 index f7304dd3b5..0000000000 --- a/tests/functional/data/contracts/ethereum/local/vyper_math_dev_checks.json +++ /dev/null @@ -1 +0,0 @@ -{"abi":[{"inputs":[{"name":"i","type":"int128"}],"name":"num_add","outputs":[{"name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"i","type":"int128"}],"name":"neg_num_add","outputs":[{"name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"i","type":"int128"}],"name":"div_zero","outputs":[{"name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"i","type":"int128"}],"name":"mod_zero","outputs":[{"name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"}],"ast":{"ast_type":"Module","children":[{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":15,"end_col_offset":21,"end_lineno":2,"lineno":2,"src":{"jump_code":"","length":6,"start":25}}],"classification":0,"col_offset":12,"end_col_offset":21,"end_lineno":2,"lineno":2,"src":{"jump_code":"","length":9,"start":22}}],"classification":0,"col_offset":12,"end_col_offset":21,"end_lineno":2,"lineno":2,"src":{"jump_code":"","length":9,"start":22}},{"ast_type":"Return","children":[{"ast_type":"BinOp","children":[{"ast_type":"BinOp","children":[{"ast_type":"BinOp","children":[{"ast_type":"Int","children":[],"classification":0,"col_offset":12,"end_col_offset":13,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":1,"start":56}},{"ast_type":"Pow","children":[],"classification":0,"col_offset":12,"end_col_offset":18,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":6,"start":56}},{"ast_type":"Int","children":[],"classification":0,"col_offset":15,"end_col_offset":18,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":3,"start":59}}],"classification":0,"col_offset":12,"end_col_offset":18,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":6,"start":56}},{"ast_type":"Sub","children":[],"classification":0,"col_offset":12,"end_col_offset":20,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":8,"start":56}},{"ast_type":"Int","children":[],"classification":0,"col_offset":19,"end_col_offset":20,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":1,"start":63}}],"classification":0,"col_offset":12,"end_col_offset":20,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":8,"start":56}},{"ast_type":"Add","children":[],"classification":0,"col_offset":11,"end_col_offset":25,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":14,"start":55}},{"ast_type":"Name","children":[],"classification":0,"col_offset":24,"end_col_offset":25,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":1,"start":68}}],"classification":0,"col_offset":11,"end_col_offset":25,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":14,"start":55}}],"classification":0,"col_offset":4,"end_col_offset":25,"end_lineno":3,"lineno":3,"src":{"jump_code":"","length":21,"start":48}},{"ast_type":"Name","children":[],"classification":0,"col_offset":1,"end_col_offset":9,"end_lineno":1,"lineno":1,"src":{"jump_code":"","length":8,"start":1}},{"ast_type":"Name","children":[],"classification":0,"col_offset":26,"end_col_offset":32,"end_lineno":2,"lineno":2,"src":{"jump_code":"","length":6,"start":36}}],"classification":0,"col_offset":0,"end_col_offset":25,"end_lineno":3,"lineno":2,"src":{"jump_code":"","length":59,"start":10}},{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":19,"end_col_offset":25,"end_lineno":7,"lineno":7,"src":{"jump_code":"","length":6,"start":101}}],"classification":0,"col_offset":16,"end_col_offset":25,"end_lineno":7,"lineno":7,"src":{"jump_code":"","length":9,"start":98}}],"classification":0,"col_offset":16,"end_col_offset":25,"end_lineno":7,"lineno":7,"src":{"jump_code":"","length":9,"start":98}},{"ast_type":"Return","children":[{"ast_type":"BinOp","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":11,"end_col_offset":12,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":1,"start":131}},{"ast_type":"Sub","children":[],"classification":0,"col_offset":11,"end_col_offset":25,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":14,"start":131}},{"ast_type":"BinOp","children":[{"ast_type":"BinOp","children":[{"ast_type":"Int","children":[],"classification":0,"col_offset":16,"end_col_offset":17,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":1,"start":136}},{"ast_type":"Pow","children":[],"classification":0,"col_offset":16,"end_col_offset":22,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":6,"start":136}},{"ast_type":"Int","children":[],"classification":0,"col_offset":19,"end_col_offset":22,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":3,"start":139}}],"classification":0,"col_offset":16,"end_col_offset":22,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":6,"start":136}},{"ast_type":"Sub","children":[],"classification":0,"col_offset":16,"end_col_offset":24,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":8,"start":136}},{"ast_type":"Int","children":[],"classification":0,"col_offset":23,"end_col_offset":24,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":1,"start":143}}],"classification":0,"col_offset":16,"end_col_offset":24,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":8,"start":136}}],"classification":0,"col_offset":11,"end_col_offset":25,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":14,"start":131}}],"classification":0,"col_offset":4,"end_col_offset":25,"end_lineno":8,"lineno":8,"src":{"jump_code":"","length":21,"start":124}},{"ast_type":"Name","children":[],"classification":0,"col_offset":1,"end_col_offset":9,"end_lineno":6,"lineno":6,"src":{"jump_code":"","length":8,"start":73}},{"ast_type":"Name","children":[],"classification":0,"col_offset":30,"end_col_offset":36,"end_lineno":7,"lineno":7,"src":{"jump_code":"","length":6,"start":112}}],"classification":0,"col_offset":0,"end_col_offset":25,"end_lineno":8,"lineno":7,"src":{"jump_code":"","length":63,"start":82}},{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":16,"end_col_offset":22,"end_lineno":12,"lineno":12,"src":{"jump_code":"","length":6,"start":174}}],"classification":0,"col_offset":13,"end_col_offset":22,"end_lineno":12,"lineno":12,"src":{"jump_code":"","length":9,"start":171}}],"classification":0,"col_offset":13,"end_col_offset":22,"end_lineno":12,"lineno":12,"src":{"jump_code":"","length":9,"start":171}},{"ast_type":"Return","children":[{"ast_type":"BinOp","children":[{"ast_type":"Int","children":[],"classification":0,"col_offset":11,"end_col_offset":12,"end_lineno":13,"lineno":13,"src":{"jump_code":"","length":1,"start":204}},{"ast_type":"Div","children":[],"classification":0,"col_offset":11,"end_col_offset":16,"end_lineno":13,"lineno":13,"src":{"jump_code":"","length":5,"start":204}},{"ast_type":"Name","children":[],"classification":0,"col_offset":15,"end_col_offset":16,"end_lineno":13,"lineno":13,"src":{"jump_code":"","length":1,"start":208}}],"classification":0,"col_offset":11,"end_col_offset":16,"end_lineno":13,"lineno":13,"src":{"jump_code":"","length":5,"start":204}}],"classification":0,"col_offset":4,"end_col_offset":16,"end_lineno":13,"lineno":13,"src":{"jump_code":"","length":12,"start":197}},{"ast_type":"Name","children":[],"classification":0,"col_offset":1,"end_col_offset":9,"end_lineno":11,"lineno":11,"src":{"jump_code":"","length":8,"start":149}},{"ast_type":"Name","children":[],"classification":0,"col_offset":27,"end_col_offset":33,"end_lineno":12,"lineno":12,"src":{"jump_code":"","length":6,"start":185}}],"classification":0,"col_offset":0,"end_col_offset":16,"end_lineno":13,"lineno":12,"src":{"jump_code":"","length":51,"start":158}},{"ast_type":"FunctionDef","children":[{"ast_type":"arguments","children":[{"ast_type":"arg","children":[{"ast_type":"Name","children":[],"classification":0,"col_offset":16,"end_col_offset":22,"end_lineno":17,"lineno":17,"src":{"jump_code":"","length":6,"start":238}}],"classification":0,"col_offset":13,"end_col_offset":22,"end_lineno":17,"lineno":17,"src":{"jump_code":"","length":9,"start":235}}],"classification":0,"col_offset":13,"end_col_offset":22,"end_lineno":17,"lineno":17,"src":{"jump_code":"","length":9,"start":235}},{"ast_type":"Return","children":[{"ast_type":"BinOp","children":[{"ast_type":"Int","children":[],"classification":0,"col_offset":11,"end_col_offset":12,"end_lineno":18,"lineno":18,"src":{"jump_code":"","length":1,"start":268}},{"ast_type":"Mod","children":[],"classification":0,"col_offset":11,"end_col_offset":16,"end_lineno":18,"lineno":18,"src":{"jump_code":"","length":5,"start":268}},{"ast_type":"Name","children":[],"classification":0,"col_offset":15,"end_col_offset":16,"end_lineno":18,"lineno":18,"src":{"jump_code":"","length":1,"start":272}}],"classification":0,"col_offset":11,"end_col_offset":16,"end_lineno":18,"lineno":18,"src":{"jump_code":"","length":5,"start":268}}],"classification":0,"col_offset":4,"end_col_offset":16,"end_lineno":18,"lineno":18,"src":{"jump_code":"","length":12,"start":261}},{"ast_type":"Name","children":[],"classification":0,"col_offset":1,"end_col_offset":9,"end_lineno":16,"lineno":16,"src":{"jump_code":"","length":8,"start":213}},{"ast_type":"Name","children":[],"classification":0,"col_offset":27,"end_col_offset":33,"end_lineno":17,"lineno":17,"src":{"jump_code":"","length":6,"start":249}}],"classification":0,"col_offset":0,"end_col_offset":16,"end_lineno":18,"lineno":17,"src":{"jump_code":"","length":51,"start":222}}],"classification":0,"col_offset":0,"end_col_offset":16,"end_lineno":18,"lineno":1,"src":{"jump_code":"","length":273}},"contractName":"VyperMathDevChecks","deploymentBytecode":{"bytecode":"0x61014361001161000039610143610000f36003361161000c5761012b565b60003560e01c3461013157637c6ad633811861006557602436106101315760043580600f0b811861013157604052604051806f7fffffffffffffffffffffffffffffff0180600f0b811861013157905060605260206060f35b636111b54481186100b357602436106101315760043580600f0b8118610131576040526040516f7fffffffffffffffffffffffffffffff810380600f0b811861013157905060605260206060f35b63193755ff81186100ee57602436106101315760043580600f0b81186101315760405260405180156101315780600405905060605260206060f35b63503eae2b811861012957602436106101315760043580600f0b81186101315760405260405180156101315780600407905060605260206060f35b505b60006000fd5b600080fda165767970657283000307000b"},"dev_messages":{},"devdoc":{},"pcmap":{"120":{"dev":"dev: Cannot send ether to non-payable function","location":null},"134":{"location":[7,16,7,25]},"136":{"location":[7,16,7,25]},"137":{"location":[8,11,8,12]},"139":{"location":[8,11,8,25]},"140":{"location":[8,16,8,24]},"157":{"dev":"dev: Integer underflow","location":[8,11,8,25]},"169":{"location":[8,11,8,25]},"170":{"location":[8,11,8,25]},"198":{"dev":"dev: Cannot send ether to non-payable function","location":null},"212":{"location":[12,13,12,22]},"214":{"location":[12,13,12,22]},"215":{"location":[13,15,13,16]},"217":{"location":[13,11,13,16]},"218":{"dev":"dev: Division by zero","location":[13,11,13,16]},"224":{"location":[13,11,13,16]},"225":{"location":[13,11,13,12]},"228":{"location":[13,11,13,16]},"229":{"location":[13,11,13,16]},"23":{"dev":"dev: Cannot send ether to non-payable function","location":null},"257":{"dev":"dev: Cannot send ether to non-payable function","location":null},"271":{"location":[17,13,17,22]},"273":{"location":[17,13,17,22]},"274":{"location":[18,15,18,16]},"276":{"location":[18,11,18,16]},"277":{"dev":"dev: Modulo by zero","location":[18,11,18,16]},"283":{"location":[18,11,18,16]},"284":{"location":[18,11,18,12]},"286":{"location":[18,11,18,16]},"287":{"location":[18,11,18,16]},"288":{"location":[18,11,18,16]},"42":{"dev":"dev: Cannot send ether to non-payable function","location":null},"56":{"location":[2,12,2,21]},"58":{"location":[2,12,2,21]},"59":{"location":[3,24,3,25]},"61":{"location":[3,11,3,25]},"62":{"location":[3,11,3,25]},"63":{"dev":"dev: Integer overflow","location":[3,12,3,20]},"91":{"location":[3,11,3,25]},"92":{"location":[3,11,3,25]}},"runtimeBytecode":{"bytecode":"0x6003361161000c5761012b565b60003560e01c3461013157637c6ad633811861006557602436106101315760043580600f0b811861013157604052604051806f7fffffffffffffffffffffffffffffff0180600f0b811861013157905060605260206060f35b636111b54481186100b357602436106101315760043580600f0b8118610131576040526040516f7fffffffffffffffffffffffffffffff810380600f0b811861013157905060605260206060f35b63193755ff81186100ee57602436106101315760043580600f0b81186101315760405260405180156101315780600405905060605260206060f35b63503eae2b811861012957602436106101315760043580600f0b81186101315760405260405180156101315780600407905060605260206060f35b505b60006000fd5b600080fda165767970657283000307000b"},"sourceId":"vyper_math_dev_checks.json","sourcemap":"-1:-1:0:-;;;;:::-;;:::-;:::-;;;;;;;:::-;;;;;:::-;;;;;:::-;;;;;;;;;:::-;22:9;;68:1;55:14;;56:8;-1:-1;;;;;;;:::-;55:14;;-1:-1;;;;;:::-;;;;;:::-;;;;;:::-;;;;;;;;;:::-;98:9;;131:1;:14;136:8;131:14;-1:-1;;;;;;;:::-;131:14;;-1:-1;;;;;:::-;;;;;:::-;;;;;:::-;;;;;;;;;:::-;171:9;;208:1;204:5;;-1:-1;;:::-;204:5;:1;-1:-1;204:5;;-1:-1;;;;;:::-;;;;;:::-;;;;;:::-;;;;;;;;;:::-;235:9;;272:1;268:5;;-1:-1;;:::-;268:5;:1;:5;;;-1:-1;;;;;:::-;;:::-;;;;:::-;;;","userdoc":{}} diff --git a/tests/functional/data/sources/RevertsContractVy.vy b/tests/functional/data/sources/RevertsContract.vy similarity index 91% rename from tests/functional/data/sources/RevertsContractVy.vy rename to tests/functional/data/sources/RevertsContract.vy index 33bee396b6..1b09583dd0 100644 --- a/tests/functional/data/sources/RevertsContractVy.vy +++ b/tests/functional/data/sources/RevertsContract.vy @@ -1,12 +1,12 @@ # @version 0.3.7 -import interfaces.ISubRevertsVy as ISubRevertsVy +import interfaces.ISubReverts as ISubReverts -sub_reverts: public(ISubRevertsVy) +sub_reverts: public(ISubReverts) MAX_NUM: constant(uint256) = 32 @external -def __init__(sub_reverts: ISubRevertsVy): +def __init__(sub_reverts: ISubReverts): self.sub_reverts = sub_reverts @external diff --git a/tests/functional/data/sources/interfaces/ISubRevertsVy.vy b/tests/functional/data/sources/interfaces/ISubReverts.vy similarity index 100% rename from tests/functional/data/sources/interfaces/ISubRevertsVy.vy rename to tests/functional/data/sources/interfaces/ISubReverts.vy diff --git a/tests/functional/test_geth.py b/tests/functional/test_geth.py index fd01e28853..49ec2cd56b 100644 --- a/tests/functional/test_geth.py +++ b/tests/functional/test_geth.py @@ -372,17 +372,6 @@ def run_test(): run_test() -@geth_process_test -def test_contract_logic_error_dev_message(vyper_math_dev_check, owner, geth_provider): - contract = vyper_math_dev_check.deploy(sender=owner) - expected = "dev: Integer overflow" - with pytest.raises(ContractLogicError, match=expected) as err: - contract.num_add(1, sender=owner) - - assert err.value.txn is not None - assert err.value.dev_message == expected - - def assert_rich_output(rich_capture: List[str], expected: str): expected_lines = [x.rstrip() for x in expected.splitlines() if x.rstrip()] actual_lines = [x.rstrip() for x in rich_capture if x.rstrip()] diff --git a/tests/functional/test_reverts_context_manager.py b/tests/functional/test_reverts_context_manager.py index ea3f3e0728..d822eabb3d 100644 --- a/tests/functional/test_reverts_context_manager.py +++ b/tests/functional/test_reverts_context_manager.py @@ -3,7 +3,6 @@ import pytest from ape.pytest.contextmanagers import RevertsContextManager as reverts -from tests.conftest import geth_process_test def test_revert_info_context(owner, reverts_contract_instance): @@ -141,140 +140,3 @@ def test_revert_partial_fails(owner, reverts_contract_instance): with pytest.raises(AssertionError): with reverts("ze"): reverts_contract_instance.revertStrings(0, sender=owner) - - -@geth_process_test -def test_dev_revert(owner, reverts_contract_instance, geth_provider): - """ - Test matching a contract dev revert message with a supplied dev message. - """ - with reverts(dev_message="dev: error"): - reverts_contract_instance.revertStrings(2, sender=owner) - - # Show a method further down in the contract also works. - with reverts(dev_message="dev: error"): - reverts_contract_instance.revertStrings2(2, sender=owner) - - -@geth_process_test -def test_dev_revert_pattern(owner, reverts_contract_instance, geth_provider): - """ - Test matching a contract dev revert message with a supplied dev message pattern. - """ - with reverts(dev_message=re.compile(r"dev: err\w+")): - reverts_contract_instance.revertStrings(2, sender=owner) - - with reverts(dev_message=re.compile(r"dev: err\w+")): - reverts_contract_instance.revertStrings2(2, sender=owner) - - -@geth_process_test -def test_dev_revert_from_sub_contract(owner, reverts_contract_instance, geth_provider): - """ - Test to ensure we can assert on dev messages from inner-contracts. - """ - with reverts(dev_message="dev: sub-zero"): - reverts_contract_instance.subRevertStrings(0, sender=owner) - - -@geth_process_test -def test_dev_revert_deep_in_method(owner, reverts_contract_instance, geth_provider): - """ - Test to ensure we can assert on a dev message that is in the middle of a - complicated function implementation. - """ - with reverts(dev_message="dev: foobarbaz"): - reverts_contract_instance.revertStrings(13, sender=owner) - - with reverts(dev_message="dev: such modifiable, wow"): - reverts_contract_instance.revertStrings(4, sender=owner) - - with reverts(dev_message="dev: great job"): - reverts_contract_instance.revertStrings(31337, sender=owner) - - -def test_dev_revert_in_loop(owner, reverts_contract_instance, geth_provider): - with reverts(dev_message="dev: loop test"): - reverts_contract_instance.revertStrings2(12, sender=owner) - - -@geth_process_test -def test_dev_revert_nonpayable_check(owner, vyper_contract_container, geth_provider): - """ - Tests that we can assert on dev messages injected from the compiler. - """ - contract = owner.deploy(vyper_contract_container, 0) - with reverts(dev_message="dev: Cannot send ether to non-payable function"): - contract.setNumber(123, sender=owner, value=1) - - -@geth_process_test -def test_dev_revert_math_dev_checks(owner, vyper_math_dev_check, geth_provider): - """ - Tests that we can assert on dev messages injected from the compiler. - """ - contract = owner.deploy(vyper_math_dev_check) - - with reverts(dev_message="dev: Integer overflow"): - contract.num_add(1, sender=owner) - - with reverts(dev_message="dev: Integer underflow"): - contract.neg_num_add(-2, sender=owner) - - with reverts(dev_message="dev: Division by zero"): - contract.div_zero(0, sender=owner) - - with reverts(dev_message="dev: Modulo by zero"): - contract.mod_zero(0, sender=owner) - - -@geth_process_test -def test_dev_revert_fails(owner, reverts_contract_instance, geth_provider): - """ - Test that ``AssertionError`` is raised if the supplied dev message and the contract dev message - do not match. - """ - with pytest.raises(AssertionError): - with reverts(dev_message="dev: foo"): - reverts_contract_instance.revertStrings(2, sender=owner) - - -@geth_process_test -def test_dev_revert_partial_fails(owner, reverts_contract_instance, geth_provider): - """ - Test that ``AssertionError`` is raised if the supplied dev message and the contract dev message - do not match exactly. - """ - with pytest.raises(AssertionError): - with reverts(dev_message="dev: foo"): - reverts_contract_instance.revertStrings(2, sender=owner) - - -@geth_process_test -def test_dev_revert_pattern_fails(owner, reverts_contract_instance, geth_provider): - """ - Test that ``AssertionError`` is raised if the contract dev message does not match the supplied - dev revert pattern. - """ - with pytest.raises(AssertionError): - with reverts(dev_message=re.compile(r"dev: [^ero]+")): - reverts_contract_instance.revertStrings(2, sender=owner) - - -@geth_process_test -def test_dev_revert_on_call(owner, reverts_contract_instance, geth_provider): - """ - Shows that dev strings are detectable even on pure / view methods. - """ - with reverts(dev_message="dev: one"): - reverts_contract_instance.revertStringsCall(1) - - -@geth_process_test -def test_both_message_and_dev_str(owner, reverts_contract_instance, geth_provider): - """ - Test matching a revert message with a supplied message as well as a contract dev revert message - with a supplied dev message. - """ - with reverts(expected_message="two", dev_message="dev: error"): - reverts_contract_instance.revertStrings(2, sender=owner)