[svn r57321] merging the event branch:
* moving in test, misc, code, io directories and py/__init__.py * py/bin/_find.py does not print to stderr anymore * a few fixes to conftest files in other dirs some more fixes and adjustments pending --HG-- branch : trunk
This commit is contained in:
230
py/test/testing/suptest.py
Normal file
230
py/test/testing/suptest.py
Normal file
@@ -0,0 +1,230 @@
|
||||
"""
|
||||
test support code
|
||||
|
||||
makeuniquepyfile(source) generates a per-test-run-unique directory and test_*.py file
|
||||
|
||||
for analyzing events an EventSorter instance is returned for both of:
|
||||
* events_from_cmdline(args): inprocess-run of cmdline invocation
|
||||
* events_from_session(session): inprocess-run of given session
|
||||
* events_run_example(examplename, *args):in-process-run of
|
||||
given example test file
|
||||
|
||||
eventappender(config): for getting all events in a list:
|
||||
"""
|
||||
import py
|
||||
from py.__.test import event
|
||||
from fnmatch import fnmatch
|
||||
|
||||
def eventappender(session):
|
||||
l = []
|
||||
def app(ev):
|
||||
print ev
|
||||
l.append(ev)
|
||||
session.bus.subscribe(app)
|
||||
return l
|
||||
|
||||
def initsorter_from_cmdline(args=None):
|
||||
if args is None:
|
||||
args = []
|
||||
config = py.test.config._reparse(args)
|
||||
session = config.initsession()
|
||||
sorter = EventSorter(config, session)
|
||||
return sorter
|
||||
|
||||
def getcolitems(config):
|
||||
return [config.getfsnode(arg) for arg in config.args]
|
||||
|
||||
def events_from_cmdline(args=None):
|
||||
sorter = initsorter_from_cmdline(args)
|
||||
sorter.session.main(getcolitems(sorter.session.config))
|
||||
return sorter
|
||||
|
||||
def events_from_runsource(source):
|
||||
source = py.code.Source(source)
|
||||
tfile = makeuniquepyfile(source)
|
||||
return events_from_cmdline([tfile])
|
||||
|
||||
def events_from_session(session):
|
||||
sorter = EventSorter(session.config, session)
|
||||
session.main(getcolitems(session.config))
|
||||
return sorter
|
||||
|
||||
def events_run_example(examplename, *args):
|
||||
from setupdata import getexamplefile
|
||||
p = getexamplefile(examplename)
|
||||
return events_from_cmdline([p] + list(args))
|
||||
|
||||
class EventSorter(object):
|
||||
def __init__(self, config, session=None):
|
||||
self.config = config
|
||||
self.session = session
|
||||
self.cls2events = d = {}
|
||||
def app(event):
|
||||
print "[event]", event
|
||||
for cls in py.std.inspect.getmro(event.__class__):
|
||||
if cls is not object:
|
||||
d.setdefault(cls, []).append(event)
|
||||
session.bus.subscribe(app)
|
||||
|
||||
def get(self, cls):
|
||||
return self.cls2events.get(cls, [])
|
||||
|
||||
def listoutcomes(self):
|
||||
passed = []
|
||||
skipped = []
|
||||
failed = []
|
||||
for ev in self.get(event.ItemTestReport):
|
||||
if ev.passed:
|
||||
passed.append(ev)
|
||||
elif ev.skipped:
|
||||
skipped.append(ev)
|
||||
elif ev.failed:
|
||||
failed.append(ev)
|
||||
return passed, skipped, failed
|
||||
|
||||
def countoutcomes(self):
|
||||
return map(len, self.listoutcomes())
|
||||
|
||||
def assertoutcome(self, passed=0, skipped=0, failed=0):
|
||||
realpassed, realskipped, realfailed = self.listoutcomes()
|
||||
assert passed == len(realpassed)
|
||||
assert skipped == len(realskipped)
|
||||
assert failed == len(realfailed)
|
||||
|
||||
def getfailedcollections(self):
|
||||
l = []
|
||||
for ev in self.get(event.CollectionReport):
|
||||
if ev.failed:
|
||||
l.append(ev)
|
||||
return l
|
||||
|
||||
def getreport(self, inamepart):
|
||||
""" return a testreport whose dotted import path matches """
|
||||
l = []
|
||||
for rep in self.get(event.ItemTestReport):
|
||||
if inamepart in rep.colitem.listnames():
|
||||
l.append(rep)
|
||||
if len(l) != 1:
|
||||
raise ValueError("did not find exactly one testreport"
|
||||
"found" + str(l))
|
||||
return l[0]
|
||||
|
||||
|
||||
counter = py.std.itertools.count().next
|
||||
def makeuniquepyfile(source):
|
||||
dirname = "test_%d" %(counter(),)
|
||||
tmpdir = py.test.ensuretemp(dirname)
|
||||
p = tmpdir.join(dirname + ".py")
|
||||
assert not p.check()
|
||||
p.write(py.code.Source(source))
|
||||
print "created test file", p
|
||||
p.dirpath("__init__.py").ensure()
|
||||
return p
|
||||
|
||||
def getItemTestReport(source, tb="long"):
|
||||
tfile = makeuniquepyfile(source)
|
||||
sorter = events_from_cmdline([tfile, "--tb=%s" %tb])
|
||||
# get failure base info
|
||||
failevents = sorter.get(event.ItemTestReport)
|
||||
assert len(failevents) == 1
|
||||
return failevents[0],tfile
|
||||
|
||||
def assert_lines_contain_lines(lines1, lines2):
|
||||
""" assert that lines2 are contained (linearly) in lines1.
|
||||
return a list of extralines found.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
if isinstance(lines2, str):
|
||||
lines2 = py.code.Source(lines2)
|
||||
if isinstance(lines2, py.code.Source):
|
||||
lines2 = lines2.strip().lines
|
||||
|
||||
extralines = []
|
||||
lines1 = lines1[:]
|
||||
nextline = None
|
||||
for line in lines2:
|
||||
nomatchprinted = False
|
||||
while lines1:
|
||||
nextline = lines1.pop(0)
|
||||
if line == nextline:
|
||||
print "exact match:", repr(line)
|
||||
break
|
||||
elif fnmatch(nextline, line):
|
||||
print "fnmatch:", repr(line)
|
||||
print " with:", repr(nextline)
|
||||
break
|
||||
else:
|
||||
if not nomatchprinted:
|
||||
print "nomatch:", repr(line)
|
||||
nomatchprinted = True
|
||||
print " and:", repr(nextline)
|
||||
extralines.append(nextline)
|
||||
else:
|
||||
if line != nextline:
|
||||
#__tracebackhide__ = True
|
||||
raise AssertionError("expected line not found: %r" % line)
|
||||
extralines.extend(lines1)
|
||||
return extralines
|
||||
|
||||
# XXX below some code to help with inlining examples
|
||||
# as source code.
|
||||
#
|
||||
class FileCreation(object):
|
||||
def setup_method(self, method):
|
||||
self.tmpdir = py.test.ensuretemp("%s_%s" %
|
||||
(self.__class__.__name__, method.__name__))
|
||||
def makepyfile(self, **kwargs):
|
||||
return self._makefile('.py', **kwargs)
|
||||
def maketxtfile(self, **kwargs):
|
||||
return self._makefile('.txt', **kwargs)
|
||||
def _makefile(self, ext, **kwargs):
|
||||
ret = None
|
||||
for name, value in kwargs.iteritems():
|
||||
p = self.tmpdir.join(name).new(ext=ext)
|
||||
source = py.code.Source(value)
|
||||
p.write(str(py.code.Source(value)).lstrip())
|
||||
if ret is None:
|
||||
ret = p
|
||||
return ret
|
||||
|
||||
class InlineCollection(FileCreation):
|
||||
""" helps to collect and run test functions inlining other test functions. """
|
||||
|
||||
def getmodulecol(self, source, configargs=(), withsession=False):
|
||||
self.tmpdir.ensure("__init__.py")
|
||||
kw = {self.tmpdir.basename: py.code.Source(source).strip()}
|
||||
path = self.makepyfile(**kw)
|
||||
self.config = self.parseconfig(path, *configargs)
|
||||
if withsession:
|
||||
self.session = self.config.initsession()
|
||||
return self.config.getfsnode(path)
|
||||
|
||||
def parseconfig(self, *args):
|
||||
return py.test.config._reparse(list(args))
|
||||
|
||||
def getitems(self, source):
|
||||
modulecol = self.getmodulecol(source)
|
||||
return [modulecol.join(x) for x in modulecol.listdir()]
|
||||
|
||||
def getitem(self, source, funcname="test_func"):
|
||||
modulecol = self.getmodulecol(source)
|
||||
item = modulecol.join(funcname)
|
||||
assert item is not None, "%r item not found in module:\n%s" %(funcname, source)
|
||||
return item
|
||||
|
||||
def runitem(self, func, funcname="test_func", **runnerargs):
|
||||
item = self.getitem(func, funcname=funcname)
|
||||
runner = self.getrunner()
|
||||
return runner(item, **runnerargs)
|
||||
|
||||
|
||||
def popvalue(stringio):
|
||||
value = stringio.getvalue().rstrip()
|
||||
stringio.truncate(0)
|
||||
return value
|
||||
|
||||
def assert_stringio_contains_lines(stringio, tomatchlines):
|
||||
stringio.seek(0)
|
||||
l = stringio.readlines()
|
||||
l = map(str.rstrip, l)
|
||||
assert_lines_contain_lines(l, tomatchlines)
|
||||
Reference in New Issue
Block a user