168 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
import py
 | 
						|
import sys
 | 
						|
from py.__.test.outcome import Outcome, Failed, Passed, Skipped
 | 
						|
from py.__.test.reporter import choose_reporter, TestReporter
 | 
						|
from py.__.test import repevent
 | 
						|
from py.__.test.outcome import SerializableOutcome, ReprOutcome
 | 
						|
from py.__.test.reporter import LocalReporter
 | 
						|
from py.__.test.executor import RunExecutor, BoxExecutor
 | 
						|
 | 
						|
""" The session implementation - reporter version:
 | 
						|
 | 
						|
* itemgen is responsible for iterating and telling reporter
 | 
						|
  about skipped and failed iterations (this is for collectors only),
 | 
						|
  this should be probably moved to session (for uniformity)
 | 
						|
* session gets items which needs to be executed one after another
 | 
						|
  and tells reporter about that
 | 
						|
"""
 | 
						|
 | 
						|
try:
 | 
						|
    GeneratorExit
 | 
						|
except NameError:
 | 
						|
    GeneratorExit = StopIteration # I think
 | 
						|
 | 
						|
def itemgen(session, colitems, reporter, keyword=None):
 | 
						|
    stopitems = py.test.collect.Item # XXX should be generator here as well
 | 
						|
    while 1:
 | 
						|
        if not colitems:
 | 
						|
            break
 | 
						|
        next = colitems.pop(0)
 | 
						|
        if reporter: 
 | 
						|
            reporter(repevent.ItemStart(next))
 | 
						|
 | 
						|
        if isinstance(next, stopitems):
 | 
						|
            try:
 | 
						|
                next._skipbykeyword(keyword)
 | 
						|
                if session and session.config.option.keyword_oneshot:
 | 
						|
                    keyword = None
 | 
						|
                yield next
 | 
						|
            except Skipped:
 | 
						|
                excinfo = py.code.ExceptionInfo()
 | 
						|
                reporter(repevent.SkippedTryiter(excinfo, next))
 | 
						|
        else:
 | 
						|
            try:
 | 
						|
                cols = [next.join(x) for x in next.run()]
 | 
						|
                for x in itemgen(session, cols, reporter, keyword):
 | 
						|
                    yield x
 | 
						|
            except (KeyboardInterrupt, SystemExit, GeneratorExit):
 | 
						|
                raise
 | 
						|
            except:
 | 
						|
                excinfo = py.code.ExceptionInfo()
 | 
						|
                if excinfo.type is Skipped:
 | 
						|
                    reporter(repevent.SkippedTryiter(excinfo, next))
 | 
						|
                else:
 | 
						|
                    reporter(repevent.FailedTryiter(excinfo, next))
 | 
						|
                    if session.config.option.usepdb: 
 | 
						|
                        py.__.test.custompdb.post_mortem(excinfo._excinfo[2])
 | 
						|
        if reporter: 
 | 
						|
            reporter(repevent.ItemFinish(next))
 | 
						|
 | 
						|
class AbstractSession(object): 
 | 
						|
    """ An abstract session executes collectors/items through a runner. 
 | 
						|
    """
 | 
						|
    def __init__(self, config):
 | 
						|
        self.config = config
 | 
						|
        self._keyword = config.option.keyword
 | 
						|
 | 
						|
    def fixoptions(self):
 | 
						|
        """ check, fix and determine conflicting options. """
 | 
						|
        option = self.config.option 
 | 
						|
        if option.runbrowser and not option.startserver:
 | 
						|
            #print "--runbrowser implies --startserver"
 | 
						|
            option.startserver = True
 | 
						|
        if self.config.getvalue("dist_boxed") and option.dist:
 | 
						|
            option.boxed = True
 | 
						|
        # conflicting options
 | 
						|
        if option.looponfailing and option.usepdb:
 | 
						|
            raise ValueError, "--looponfailing together with --pdb not supported."
 | 
						|
        if option.looponfailing and option.dist:
 | 
						|
            raise ValueError, "--looponfailing together with --dist not supported."
 | 
						|
        if option.executable and option.usepdb:
 | 
						|
            raise ValueError, "--exec together with --pdb not supported."
 | 
						|
 | 
						|
        if option.keyword_oneshot and not option.keyword:
 | 
						|
            raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied"
 | 
						|
 | 
						|
    def init_reporter(self, reporter, config, hosts):
 | 
						|
        if reporter is None:
 | 
						|
            reporter = choose_reporter(self.reporterclass, config)\
 | 
						|
                       (config, hosts)
 | 
						|
        else:
 | 
						|
            reporter = TestReporter(reporter)
 | 
						|
        checkfun = lambda : self.config.option.exitfirst and \
 | 
						|
                            reporter.was_failure()
 | 
						|
        return reporter, checkfun
 | 
						|
 | 
						|
class Session(AbstractSession):
 | 
						|
    """
 | 
						|
        A Session gets test Items from Collectors, executes the
 | 
						|
        Items and sends the Outcome to the Reporter.
 | 
						|
    """
 | 
						|
    reporterclass = LocalReporter
 | 
						|
    
 | 
						|
    def shouldclose(self): 
 | 
						|
        return False
 | 
						|
 | 
						|
    def header(self, colitems):
 | 
						|
        """ setup any neccessary resources ahead of the test run. """
 | 
						|
        self.reporter(repevent.TestStarted(None, self.config,
 | 
						|
                                            None))
 | 
						|
        if not self.config.option.nomagic:
 | 
						|
            py.magic.invoke(assertion=1)
 | 
						|
 | 
						|
    def footer(self, colitems):
 | 
						|
        """ teardown any resources after a test run. """ 
 | 
						|
        py.test.collect.Function._state.teardown_all()
 | 
						|
        if not self.config.option.nomagic:
 | 
						|
            py.magic.revoke(assertion=1)
 | 
						|
        self.reporter(repevent.TestFinished())
 | 
						|
    
 | 
						|
    def main(self, reporter=None):
 | 
						|
        """ main loop for running tests. """
 | 
						|
        config = self.config
 | 
						|
        self.reporter, shouldstop = self.init_reporter(reporter, config, None)
 | 
						|
 | 
						|
        colitems = self.config.getcolitems()
 | 
						|
        self.header(colitems)
 | 
						|
        keyword = self.config.option.keyword
 | 
						|
        reporter = self.reporter
 | 
						|
        itemgenerator = itemgen(self, colitems, reporter, keyword)
 | 
						|
        failures = []
 | 
						|
        try:
 | 
						|
            while 1:
 | 
						|
                try:
 | 
						|
                    item = itemgenerator.next()
 | 
						|
                    if shouldstop():
 | 
						|
                        return
 | 
						|
                    outcome = self.run(item)
 | 
						|
                    if outcome is not None: 
 | 
						|
                        if not outcome.passed and not outcome.skipped: 
 | 
						|
                            failures.append((item, outcome))
 | 
						|
                    reporter(repevent.ReceivedItemOutcome(None, item, outcome))
 | 
						|
                except StopIteration:
 | 
						|
                    break
 | 
						|
        finally:
 | 
						|
            self.footer(colitems)
 | 
						|
        return failures 
 | 
						|
        return self.getitemoutcomepairs(Failed)
 | 
						|
 | 
						|
    def run(self, item):
 | 
						|
        if not self.config.option.boxed:
 | 
						|
            executor = RunExecutor(item, self.config.option.usepdb,
 | 
						|
                                   self.reporter, self.config)
 | 
						|
            return ReprOutcome(executor.execute().make_repr())
 | 
						|
        else:
 | 
						|
            executor = BoxExecutor(item, self.config.option.usepdb,
 | 
						|
                                   self.reporter, self.config)
 | 
						|
            return ReprOutcome(executor.execute())
 | 
						|
 | 
						|
class Exit(Exception):
 | 
						|
    """ for immediate program exits without tracebacks and reporter/summary. """
 | 
						|
    def __init__(self, msg="unknown reason", item=None):
 | 
						|
        self.msg = msg 
 | 
						|
        Exception.__init__(self, msg)
 | 
						|
 | 
						|
def exit(msg, item=None): 
 | 
						|
    raise Exit(msg=msg, item=item)
 | 
						|
 |