Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow regex in brownie.reverts #864

Merged
merged 4 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions brownie/test/managers/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import builtins
import json
import re
import sys
import warnings
from pathlib import Path
Expand Down Expand Up @@ -47,9 +48,23 @@ def revert_deprecation(revert_msg=None):


class RevertContextManager:
def __init__(self, revert_msg=None, dev_revert_msg=None):
def __init__(
self, revert_msg=None, dev_revert_msg=None, revert_pattern=None, dev_revert_pattern=None
):
if revert_msg is not None and revert_pattern is not None:
raise ValueError("Can only use one of`revert_msg` and `revert_pattern`")
if dev_revert_msg is not None and dev_revert_pattern is not None:
raise ValueError("Can only use one of `dev_revert_msg` and `dev_revert_pattern`")

if revert_pattern:
re.compile(revert_pattern)
if dev_revert_pattern:
re.compile(dev_revert_pattern)

self.revert_msg = revert_msg
self.dev_revert_msg = dev_revert_msg
self.revert_pattern = revert_pattern
self.dev_revert_pattern = dev_revert_pattern
self.always_transact = CONFIG.argv["always_transact"]

if revert_msg is not None and (revert_msg.startswith("dev:") or dev_revert_msg):
Expand All @@ -68,15 +83,27 @@ def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not VirtualMachineError:
raise

if self.dev_revert_msg is not None and self.dev_revert_msg != exc_value.dev_revert_msg:
raise AssertionError(
f"Unexpected dev revert string '{exc_value.dev_revert_msg}'\n{exc_value.source}"
) from None

if self.revert_msg is not None and self.revert_msg != exc_value.revert_msg:
raise AssertionError(
f"Unexpected revert string '{exc_value.revert_msg}'\n{exc_value.source}"
) from None
if self.dev_revert_msg or self.dev_revert_pattern:
actual = exc_value.dev_revert_msg
if (
actual is None
or (self.dev_revert_pattern and not re.fullmatch(self.dev_revert_pattern, actual))
or (self.dev_revert_msg and self.dev_revert_msg != actual)
):
raise AssertionError(
f"Unexpected dev revert string '{actual}'\n{exc_value.source}"
) from None

if self.revert_msg or self.revert_pattern:
actual = exc_value.revert_msg
if (
actual is None
or (self.revert_pattern and not re.fullmatch(self.revert_pattern, actual))
or (self.revert_msg and self.revert_msg != actual)
):
raise AssertionError(
f"Unexpected revert string '{actual}'\n{exc_value.source}"
) from None

return True

Expand Down
6 changes: 4 additions & 2 deletions docs/api-test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,16 @@ One of these classes is instantiated in the ``pytest_configure`` method of ``bro
RevertContextManager
--------------------

The ``RevertContextManager`` closely mimics the behaviour of :func:`pytest.raises <pytest.raises>`.
The ``RevertContextManager`` behaves similarly to :func:`pytest.raises <pytest.raises>`.

.. py:class:: brownie.test.plugin.RevertContextManager(revert_msg=None, dev_revert_msg=None)
.. py:class:: brownie.test.plugin.RevertContextManager(revert_msg=None, dev_revert_msg=None, revert_pattern=None, dev_revert_pattern=None)

Context manager used to handle :func:`VirtualMachineError <brownie.exceptions.VirtualMachineError>` exceptions. Raises ``AssertionError`` if no transaction has reverted when the context closes.

* ``revert_msg``: Optional. Raises if the transaction does not revert with this error string.
* ``dev_revert_msg``: Optional. Raises if the transaction does not revert with this :ref:`dev revert string<dev-revert>`.
* ``revert_pattern``: Regex pattern to compare against the transaction error string. Raises if the error string does not fully match the regex (partial matches are not allowed).
* ``dev_revert_pattern``: Regex pattern to compare against the transaction dev revert string.

This class is available as ``brownie.reverts`` when ``pytest`` is active.

Expand Down
75 changes: 75 additions & 0 deletions tests/test/test_revert_context_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest

from brownie.test.managers.runner import RevertContextManager as reverts


def test_no_args(vypertester):
with reverts():
vypertester.revertStrings(0)


def test_revert_msg(vypertester):
with reverts("zero"):
vypertester.revertStrings(0)


def test_both(vypertester):
with reverts(revert_msg="two", dev_revert_msg="dev: error"):
vypertester.revertStrings(2)


def test_revert_msg_raises_incorrect(vypertester):
with pytest.raises(AssertionError):
with reverts("one"):
vypertester.revertStrings(0)


def test_revert_msg_raises_partial(vypertester):
with pytest.raises(AssertionError):
with reverts("ze"):
vypertester.revertStrings(0)


def test_revert_pattern(vypertester):
with reverts(revert_pattern="z..o"):
vypertester.revertStrings(0)


def test_revert_pattern_raises_incorrect(vypertester):
with pytest.raises(AssertionError):
with reverts(revert_pattern="foo[a-zA-Z]."):
vypertester.revertStrings(0)


def test_revert_pattern_raises_partial(vypertester):
with pytest.raises(AssertionError):
with reverts(revert_pattern=".ro"):
vypertester.revertStrings(0)


def test_dev_revert(vypertester):
with reverts(dev_revert_msg="dev: error"):
vypertester.revertStrings(2)


def test_dev_revert_fails(vypertester):
with pytest.raises(AssertionError):
with reverts(dev_revert_msg="dev: foo"):
vypertester.revertStrings(2)


def test_dev_revert_pattern(vypertester):
with reverts(dev_revert_pattern="[a-z]*:\\serror"):
vypertester.revertStrings(2)


def test_dev_revert_pattern_raises_incorrect(vypertester):
with pytest.raises(AssertionError):
with reverts(dev_revert_pattern="bleerg[a-zA-Z]."):
vypertester.revertStrings(2)


def test_dev_revert_pattern_raises_partial(vypertester):
with pytest.raises(AssertionError):
with reverts(dev_revert_pattern="\\sfoo"):
vypertester.revertStrings(2)
12 changes: 6 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ passenv =
GITHUB_TOKEN
WEB3_INFURA_PROJECT_ID
deps =
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: coverage==5.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest==5.4.3
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-cov==2.9.0
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-mock==3.1.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-xdist==1.32.0
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: coverage==5.2.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest==6.0.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-cov==2.10.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-mock==3.3.1
py{36,37,38},{pm,plugin}test,evm-{byzantium,petersburg,istanbul,latest}: pytest-xdist==1.34.0
docs-{local,external}: sphinx
docs-{local,external}: sphinx_rtd_theme
docs-{local,external}: pygments_lexer_solidity
Expand All @@ -27,7 +27,7 @@ commands =
evm-istanbul: python -m pytest tests/ --evm 0.5.13,0.5.17,0.6.3,0.6.9 istanbul 0,10000
evm-latest: python -m pytest tests/ --evm latest byzantium,petersburg,istanbul 0,200,10000
pmtest: python -m pytest tests/ --target pm -n 0
plugintest: python -m pytest tests/ --target plugin -n 0
plugintest: python -m pytest tests/test/plugin --target plugin -n 0
docs-local: sphinx-build {posargs:-E} -b html docs dist/docs -n -q --color
docs-external: sphinx-build -b linkcheck docs dist/docs -n -q --color

Expand Down