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

assertoutcomes() only accepts plural forms #7364

Merged
merged 1 commit into from
Jun 15, 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
20 changes: 20 additions & 0 deletions changelog/6505.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
``Testdir.run().parseoutcomes()`` now always returns the parsed nouns in plural form.

Originally ``parseoutcomes()`` would always returns the nouns in plural form, but a change
meant to improve the terminal summary by using singular form single items (``1 warning`` or ``1 error``)
caused an unintended regression by changing the keys returned by ``parseoutcomes()``.

Now the API guarantees to always return the plural form, so calls like this:

.. code-block:: python

result = testdir.runpytest()
result.assert_outcomes(error=1)

Need to be changed to:


.. code-block:: python

result = testdir.runpytest()
result.assert_outcomes(errors=1)
37 changes: 28 additions & 9 deletions src/_pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,28 +452,47 @@ def __repr__(self) -> str:
)

def parseoutcomes(self) -> Dict[str, int]:
"""Return a dictionary of outcomestring->num from parsing the terminal
"""Return a dictionary of outcome noun -> count from parsing the terminal
output that the test process produced.

The returned nouns will always be in plural form::

======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====

Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``
"""
return self.parse_summary_nouns(self.outlines)

@classmethod
def parse_summary_nouns(cls, lines) -> Dict[str, int]:
"""Extracts the nouns from a pytest terminal summary line.

It always returns the plural noun for consistency::

======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====

Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``
"""
for line in reversed(self.outlines):
for line in reversed(lines):
if rex_session_duration.search(line):
outcomes = rex_outcome.findall(line)
ret = {noun: int(count) for (count, noun) in outcomes}
break
else:
raise ValueError("Pytest terminal summary report not found")
if "errors" in ret:
assert "error" not in ret
ret["error"] = ret.pop("errors")
return ret

to_plural = {
"warning": "warnings",
"error": "errors",
}
return {to_plural.get(k, k): v for k, v in ret.items()}

def assert_outcomes(
self,
passed: int = 0,
skipped: int = 0,
failed: int = 0,
error: int = 0,
errors: int = 0,
xpassed: int = 0,
xfailed: int = 0,
) -> None:
Expand All @@ -487,15 +506,15 @@ def assert_outcomes(
"passed": d.get("passed", 0),
"skipped": d.get("skipped", 0),
"failed": d.get("failed", 0),
"error": d.get("error", 0),
"errors": d.get("errors", 0),
"xpassed": d.get("xpassed", 0),
"xfailed": d.get("xfailed", 0),
}
expected = {
"passed": passed,
"skipped": skipped,
"failed": failed,
"error": error,
"errors": errors,
"xpassed": xpassed,
"xfailed": xfailed,
}
Expand Down
2 changes: 1 addition & 1 deletion testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4342,6 +4342,6 @@ def test_fixt(custom):
)
expected = "E ValueError: custom did not yield a value"
result = testdir.runpytest()
result.assert_outcomes(error=1)
result.assert_outcomes(errors=1)
result.stdout.fnmatch_lines([expected])
assert result.ret == ExitCode.TESTS_FAILED
33 changes: 31 additions & 2 deletions testing/test_pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,9 +763,38 @@ def test_error2(bad_fixture):
"""
)
result = testdir.runpytest(str(p1))
result.assert_outcomes(error=2)
result.assert_outcomes(errors=2)

assert result.parseoutcomes() == {"error": 2}
assert result.parseoutcomes() == {"errors": 2}


def test_parse_summary_line_always_plural():
"""Parsing summaries always returns plural nouns (#6505)"""
lines = [
"some output 1",
"some output 2",
"======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====",
"done.",
]
assert pytester.RunResult.parse_summary_nouns(lines) == {
"errors": 1,
"failed": 1,
"passed": 1,
"warnings": 1,
}

lines = [
"some output 1",
"some output 2",
"======= 1 failed, 1 passed, 2 warnings, 2 errors in 0.13s ====",
"done.",
]
assert pytester.RunResult.parse_summary_nouns(lines) == {
"errors": 2,
"failed": 1,
"passed": 1,
"warnings": 2,
}


def test_makefile_joins_absolute_path(testdir: Testdir) -> None:
Expand Down