231 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
| """
 | |
|     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
 | |
|     
 | |
|     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 
 | |
| 
 | |
| 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 
 | |
| 
 | |
|     def parseconfig(self, *args):
 | |
|         return py.test.config._reparse(list(args))
 | |
|  
 | |
| 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 = {"test_" + 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 getitems(self, source):
 | |
|         modulecol = self.getmodulecol(source)
 | |
|         return modulecol.collect()
 | |
| 
 | |
|     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)
 | |
| 
 | |
| class InlineSession(InlineCollection):
 | |
|     def parse_and_run(self, *args):
 | |
|         config = self.parseconfig(*args)
 | |
|         session = config.initsession()
 | |
|         sorter = EventSorter(config, session)
 | |
|         session.main()
 | |
|         return sorter
 | |
| 
 | |
| 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)
 |