Skip to content
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
196 changes: 196 additions & 0 deletions src/_pytest/reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import py
from _pytest._code.code import TerminalRepr


def getslaveinfoline(node):
try:
return node._slaveinfocache
except AttributeError:
d = node.slaveinfo
ver = "%s.%s.%s" % d["version_info"][:3]
node._slaveinfocache = s = "[%s] %s -- Python %s %s" % (
d["id"],
d["sysplatform"],
ver,
d["executable"],
)
return s


class BaseReport(object):
def __init__(self, **kw):
self.__dict__.update(kw)

def toterminal(self, out):
if hasattr(self, "node"):
out.line(getslaveinfoline(self.node))

longrepr = self.longrepr
if longrepr is None:
return

if hasattr(longrepr, "toterminal"):
longrepr.toterminal(out)
else:
try:
out.line(longrepr)
except UnicodeEncodeError:
out.line("<unprintable longrepr>")

def get_sections(self, prefix):
for name, content in self.sections:
if name.startswith(prefix):
yield prefix, content

@property
def longreprtext(self):
"""
Read-only property that returns the full string representation
of ``longrepr``.

.. versionadded:: 3.0
"""
tw = py.io.TerminalWriter(stringio=True)
tw.hasmarkup = False
self.toterminal(tw)
exc = tw.stringio.getvalue()
return exc.strip()

@property
def caplog(self):
"""Return captured log lines, if log capturing is enabled

.. versionadded:: 3.5
"""
return "\n".join(
content for (prefix, content) in self.get_sections("Captured log")
)

@property
def capstdout(self):
"""Return captured text from stdout, if capturing is enabled

.. versionadded:: 3.0
"""
return "".join(
content for (prefix, content) in self.get_sections("Captured stdout")
)

@property
def capstderr(self):
"""Return captured text from stderr, if capturing is enabled

.. versionadded:: 3.0
"""
return "".join(
content for (prefix, content) in self.get_sections("Captured stderr")
)

passed = property(lambda x: x.outcome == "passed")
failed = property(lambda x: x.outcome == "failed")
skipped = property(lambda x: x.outcome == "skipped")

@property
def fspath(self):
return self.nodeid.split("::")[0]


class TestReport(BaseReport):
""" Basic test report object (also used for setup and teardown calls if
they fail).
"""

def __init__(
self,
nodeid,
location,
keywords,
outcome,
longrepr,
when,
sections=(),
duration=0,
user_properties=(),
**extra
):
#: normalized collection node id
self.nodeid = nodeid

#: a (filesystempath, lineno, domaininfo) tuple indicating the
#: actual location of a test item - it might be different from the
#: collected one e.g. if a method is inherited from a different module.
self.location = location

#: a name -> value dictionary containing all keywords and
#: markers associated with a test invocation.
self.keywords = keywords

#: test outcome, always one of "passed", "failed", "skipped".
self.outcome = outcome

#: None or a failure representation.
self.longrepr = longrepr

#: one of 'setup', 'call', 'teardown' to indicate runtest phase.
self.when = when

#: user properties is a list of tuples (name, value) that holds user
#: defined properties of the test
self.user_properties = user_properties

#: list of pairs ``(str, str)`` of extra information which needs to
#: marshallable. Used by pytest to add captured text
#: from ``stdout`` and ``stderr``, but may be used by other plugins
#: to add arbitrary information to reports.
self.sections = list(sections)

#: time it took to run just the test
self.duration = duration

self.__dict__.update(extra)

def __repr__(self):
return "<TestReport %r when=%r outcome=%r>" % (
self.nodeid,
self.when,
self.outcome,
)


class TeardownErrorReport(BaseReport):
outcome = "failed"
when = "teardown"

def __init__(self, longrepr, **extra):
self.longrepr = longrepr
self.sections = []
self.__dict__.update(extra)


class CollectReport(BaseReport):
def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra):
self.nodeid = nodeid
self.outcome = outcome
self.longrepr = longrepr
self.result = result or []
self.sections = list(sections)
self.__dict__.update(extra)

@property
def location(self):
return (self.fspath, None, self.fspath)

def __repr__(self):
return "<CollectReport %r lenresult=%s outcome=%r>" % (
self.nodeid,
len(self.result),
self.outcome,
)


class CollectErrorRepr(TerminalRepr):
def __init__(self, msg):
self.longrepr = msg

def toterminal(self, out):
out.line(self.longrepr, red=True)
Loading