From 0f546c4670146fbb89407cad85518e3a7dcfa833 Mon Sep 17 00:00:00 2001 From: wim glenn Date: Tue, 22 Jan 2019 23:26:30 -0600 Subject: [PATCH] pytest_terminal_summary uses result from pytest_report_teststatus hook, rather than hardcoded strings Less hacky way to make XPASS yellow markup. Make sure collect reports still have a "when" attribute. xfail changed to XFAIL in the test report, for consistency with other outcomes which are all CAPS --- changelog/4667.bugfix.rst | 1 + src/_pytest/junitxml.py | 2 +- src/_pytest/reports.py | 4 +++ src/_pytest/skipping.py | 51 +++++++++++++++++++------------------- src/_pytest/terminal.py | 8 +++--- testing/acceptance_test.py | 4 +-- testing/test_skipping.py | 2 +- testing/test_terminal.py | 2 +- 8 files changed, 41 insertions(+), 33 deletions(-) create mode 100644 changelog/4667.bugfix.rst diff --git a/changelog/4667.bugfix.rst b/changelog/4667.bugfix.rst new file mode 100644 index 000000000..ac2d8567c --- /dev/null +++ b/changelog/4667.bugfix.rst @@ -0,0 +1 @@ +``pytest_terminal_summary`` uses result from ``pytest_report_teststatus`` hook, rather than hardcoded strings. diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 1a06ea6d1..8b9af2a88 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -213,7 +213,7 @@ class _NodeReporter(object): self._add_simple(Junit.skipped, "collection skipped", report.longrepr) def append_error(self, report): - if getattr(report, "when", None) == "teardown": + if report.when == "teardown": msg = "test teardown failure" else: msg = "test setup failure" diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py index b2010cc2e..3bdbce791 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -19,6 +19,8 @@ def getslaveinfoline(node): class BaseReport(object): + when = None + def __init__(self, **kw): self.__dict__.update(kw) @@ -169,6 +171,8 @@ class TeardownErrorReport(BaseReport): class CollectReport(BaseReport): + when = "collect" + def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra): self.nodeid = nodeid self.outcome = outcome diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index f755fc4eb..9f7f525ce 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -180,9 +180,9 @@ def pytest_runtest_makereport(item, call): def pytest_report_teststatus(report): if hasattr(report, "wasxfail"): if report.skipped: - return "xfailed", "x", "xfail" + return "xfailed", "x", "XFAIL" elif report.passed: - return "xpassed", "X", ("XPASS", {"yellow": True}) + return "xpassed", "X", "XPASS" # called by the terminalreporter instance/plugin @@ -191,11 +191,6 @@ def pytest_report_teststatus(report): def pytest_terminal_summary(terminalreporter): tr = terminalreporter if not tr.reportchars: - # for name in "xfailed skipped failed xpassed": - # if not tr.stats.get(name, 0): - # tr.write_line("HINT: use '-r' option to see extra " - # "summary info about tests") - # break return lines = [] @@ -209,21 +204,23 @@ def pytest_terminal_summary(terminalreporter): tr._tw.line(line) -def show_simple(terminalreporter, lines, stat, format): +def show_simple(terminalreporter, lines, stat): failed = terminalreporter.stats.get(stat) if failed: for rep in failed: + verbose_word = _get_report_str(terminalreporter, rep) pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid) - lines.append(format % (pos,)) + lines.append("%s %s" % (verbose_word, pos)) def show_xfailed(terminalreporter, lines): xfailed = terminalreporter.stats.get("xfailed") if xfailed: for rep in xfailed: + verbose_word = _get_report_str(terminalreporter, rep) pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid) reason = rep.wasxfail - lines.append("XFAIL %s" % (pos,)) + lines.append("%s %s" % (verbose_word, pos)) if reason: lines.append(" " + str(reason)) @@ -232,9 +229,10 @@ def show_xpassed(terminalreporter, lines): xpassed = terminalreporter.stats.get("xpassed") if xpassed: for rep in xpassed: + verbose_word = _get_report_str(terminalreporter, rep) pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid) reason = rep.wasxfail - lines.append("XPASS %s %s" % (pos, reason)) + lines.append("%s %s %s" % (verbose_word, pos, reason)) def folded_skips(skipped): @@ -260,39 +258,42 @@ def show_skipped(terminalreporter, lines): tr = terminalreporter skipped = tr.stats.get("skipped", []) if skipped: - # if not tr.hasopt('skipped'): - # tr.write_line( - # "%d skipped tests, specify -rs for more info" % - # len(skipped)) - # return + verbose_word = _get_report_str(terminalreporter, report=skipped[0]) fskips = folded_skips(skipped) if fskips: - # tr.write_sep("_", "skipped test summary") for num, fspath, lineno, reason in fskips: if reason.startswith("Skipped: "): reason = reason[9:] if lineno is not None: lines.append( - "SKIP [%d] %s:%d: %s" % (num, fspath, lineno + 1, reason) + "%s [%d] %s:%d: %s" + % (verbose_word, num, fspath, lineno + 1, reason) ) else: - lines.append("SKIP [%d] %s: %s" % (num, fspath, reason)) + lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason)) -def shower(stat, format): +def shower(stat): def show_(terminalreporter, lines): - return show_simple(terminalreporter, lines, stat, format) + return show_simple(terminalreporter, lines, stat) return show_ +def _get_report_str(terminalreporter, report): + _category, _short, verbose = terminalreporter.config.hook.pytest_report_teststatus( + report=report + ) + return verbose + + REPORTCHAR_ACTIONS = { "x": show_xfailed, "X": show_xpassed, - "f": shower("failed", "FAIL %s"), - "F": shower("failed", "FAIL %s"), + "f": shower("failed"), + "F": shower("failed"), "s": show_skipped, "S": show_skipped, - "p": shower("passed", "PASSED %s"), - "E": shower("error", "ERROR %s"), + "p": shower("passed"), + "E": shower("error"), } diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index bea02306b..9e1d1cb62 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -376,8 +376,11 @@ class TerminalReporter(object): return running_xdist = hasattr(rep, "node") if markup is None: - if rep.passed: + was_xfail = hasattr(report, "wasxfail") + if rep.passed and not was_xfail: markup = {"green": True} + elif rep.passed and was_xfail: + markup = {"yellow": True} elif rep.failed: markup = {"red": True} elif rep.skipped: @@ -806,8 +809,7 @@ class TerminalReporter(object): self.write_sep("=", "ERRORS") for rep in self.stats["error"]: msg = self._getfailureheadline(rep) - if not hasattr(rep, "when"): - # collect + if rep.when == "collect": msg = "ERROR collecting " + msg elif rep.when == "setup": msg = "ERROR at setup of " + msg diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index b7f914335..af30f2123 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -804,8 +804,8 @@ class TestInvocationVariants(object): result = testdir.runpytest("-rf") lines = result.stdout.str().splitlines() for line in lines: - if line.startswith("FAIL "): - testid = line[5:].strip() + if line.startswith(("FAIL ", "FAILED ")): + _fail, _sep, testid = line.partition(" ") break result = testdir.runpytest(testid, "-rf") result.stdout.fnmatch_lines([line, "*1 failed*"]) diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 6b18011b6..be3f74760 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -1202,6 +1202,6 @@ def test_summary_list_after_errors(testdir): [ "=* FAILURES *=", "*= short test summary info =*", - "FAIL test_summary_list_after_errors.py::test_fail", + "FAILED test_summary_list_after_errors.py::test_fail", ] ) diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 06345f88d..6837da5e0 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -625,7 +625,7 @@ class TestTerminalFunctional(object): "*test_verbose_reporting.py::test_fail *FAIL*", "*test_verbose_reporting.py::test_pass *PASS*", "*test_verbose_reporting.py::TestClass::test_skip *SKIP*", - "*test_verbose_reporting.py::test_gen *xfail*", + "*test_verbose_reporting.py::test_gen *XFAIL*", ] ) assert result.ret == 1