Merge pull request #7364 from nicoddemus/parseoutcomes-plural-6505
assertoutcomes() only accepts plural forms
This commit is contained in:
commit
db00612b84
|
@ -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)
|
|
@ -452,28 +452,47 @@ class RunResult:
|
||||||
)
|
)
|
||||||
|
|
||||||
def parseoutcomes(self) -> Dict[str, int]:
|
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.
|
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}``
|
||||||
"""
|
"""
|
||||||
for line in reversed(self.outlines):
|
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(lines):
|
||||||
if rex_session_duration.search(line):
|
if rex_session_duration.search(line):
|
||||||
outcomes = rex_outcome.findall(line)
|
outcomes = rex_outcome.findall(line)
|
||||||
ret = {noun: int(count) for (count, noun) in outcomes}
|
ret = {noun: int(count) for (count, noun) in outcomes}
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError("Pytest terminal summary report not found")
|
raise ValueError("Pytest terminal summary report not found")
|
||||||
if "errors" in ret:
|
|
||||||
assert "error" not in ret
|
to_plural = {
|
||||||
ret["error"] = ret.pop("errors")
|
"warning": "warnings",
|
||||||
return ret
|
"error": "errors",
|
||||||
|
}
|
||||||
|
return {to_plural.get(k, k): v for k, v in ret.items()}
|
||||||
|
|
||||||
def assert_outcomes(
|
def assert_outcomes(
|
||||||
self,
|
self,
|
||||||
passed: int = 0,
|
passed: int = 0,
|
||||||
skipped: int = 0,
|
skipped: int = 0,
|
||||||
failed: int = 0,
|
failed: int = 0,
|
||||||
error: int = 0,
|
errors: int = 0,
|
||||||
xpassed: int = 0,
|
xpassed: int = 0,
|
||||||
xfailed: int = 0,
|
xfailed: int = 0,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -487,7 +506,7 @@ class RunResult:
|
||||||
"passed": d.get("passed", 0),
|
"passed": d.get("passed", 0),
|
||||||
"skipped": d.get("skipped", 0),
|
"skipped": d.get("skipped", 0),
|
||||||
"failed": d.get("failed", 0),
|
"failed": d.get("failed", 0),
|
||||||
"error": d.get("error", 0),
|
"errors": d.get("errors", 0),
|
||||||
"xpassed": d.get("xpassed", 0),
|
"xpassed": d.get("xpassed", 0),
|
||||||
"xfailed": d.get("xfailed", 0),
|
"xfailed": d.get("xfailed", 0),
|
||||||
}
|
}
|
||||||
|
@ -495,7 +514,7 @@ class RunResult:
|
||||||
"passed": passed,
|
"passed": passed,
|
||||||
"skipped": skipped,
|
"skipped": skipped,
|
||||||
"failed": failed,
|
"failed": failed,
|
||||||
"error": error,
|
"errors": errors,
|
||||||
"xpassed": xpassed,
|
"xpassed": xpassed,
|
||||||
"xfailed": xfailed,
|
"xfailed": xfailed,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4344,6 +4344,6 @@ def test_yield_fixture_with_no_value(testdir):
|
||||||
)
|
)
|
||||||
expected = "E ValueError: custom did not yield a value"
|
expected = "E ValueError: custom did not yield a value"
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.assert_outcomes(error=1)
|
result.assert_outcomes(errors=1)
|
||||||
result.stdout.fnmatch_lines([expected])
|
result.stdout.fnmatch_lines([expected])
|
||||||
assert result.ret == ExitCode.TESTS_FAILED
|
assert result.ret == ExitCode.TESTS_FAILED
|
||||||
|
|
|
@ -763,9 +763,38 @@ def test_testdir_outcomes_with_multiple_errors(testdir):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = testdir.runpytest(str(p1))
|
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:
|
def test_makefile_joins_absolute_path(testdir: Testdir) -> None:
|
||||||
|
|
Loading…
Reference in New Issue