Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/_pytest/assertion/rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ def visit_Assert(self, assert_):

# Passed
fmt_pass = self.helper("_format_explanation", msg)
orig = astor.to_source(assert_.test).rstrip("\n").lstrip("(").rstrip(")")
orig = astor.to_source(assert_.test).strip()
hook_call_pass = ast.Expr(
self.helper(
"_call_assertion_pass",
Expand Down
5 changes: 5 additions & 0 deletions src/_pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,17 @@ class ParsedCall:
def __init__(self, name, kwargs):
self.__dict__.update(kwargs)
self._name = name
self._kwargs = kwargs

def __repr__(self):
d = self.__dict__.copy()
del d["_name"]
return "<ParsedCall {!r}(**{!r})>".format(self._name, d)

def assert_params(self, **expected_params):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asottile this might be useful

obtained_params = {k: self._kwargs[k] for k in expected_params}
assert obtained_params == expected_params


class HookRecorder:
"""Record all hooks called in a plugin manager.
Expand Down
45 changes: 18 additions & 27 deletions testing/test_assertrewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -1335,23 +1335,25 @@ def test():


class TestAssertionPass:
@pytest.fixture
def ini(self, testdir):
testdir.makeini(
"""
[pytest]
enable_assertion_pass_hook = True
"""
)

def test_option_default(self, testdir):
config = testdir.parseconfig()
assert config.getini("enable_assertion_pass_hook") is False

def test_hook_call(self, testdir):
def test_hook_call_expr(self, testdir, ini):
testdir.makeconftest(
"""
def pytest_assertion_pass(item, lineno, orig, expl):
raise Exception("Assertion Passed: {} {} at line {}".format(orig, expl, lineno))
"""
)

testdir.makeini(
pass
"""
[pytest]
enable_assertion_pass_hook = True
"""
)

testdir.makepyfile(
Expand All @@ -1369,12 +1371,15 @@ def test_fails():
assert False, "assert with message"
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(
"*Assertion Passed: a + b == c + d (1 + 2) == (3 + 0) at line 7*"
rec = testdir.inline_run()
calls = rec.getcalls("pytest_assertion_pass")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asottile this might be useful too, using HookRecorder objects to get the hook call directly

assert len(calls) == 1
calls[0].assert_params(
orig="(a + b == c + d)", expl="(1 + 2) == (3 + 0)", lineno=7
)
assert calls[0].item.nodeid == "test_hook_call_expr.py::test_simple"

def test_hook_not_called_without_hookimpl(self, testdir, monkeypatch):
def test_hook_not_called_without_hookimpl(self, testdir, monkeypatch, ini):
"""Assertion pass should not be called (and hence formatting should
not occur) if there is no hook declared for pytest_assertion_pass"""

Expand All @@ -1385,13 +1390,6 @@ def raise_on_assertionpass(*_, **__):
_pytest.assertion.rewrite, "_call_assertion_pass", raise_on_assertionpass
)

testdir.makeini(
"""
[pytest]
enable_assertion_pass_hook = True
"""
)

testdir.makepyfile(
"""
def test_simple():
Expand Down Expand Up @@ -1424,13 +1422,6 @@ def pytest_assertion_pass(item, lineno, orig, expl):
"""
)

testdir.makeini(
"""
[pytest]
enable_assertion_pass_hook = False
"""
)

testdir.makepyfile(
"""
def test_simple():
Expand Down