blob: 927af49c74804e338746c539326c4945a883977a [file] [log] [blame]
# tests/__init__.py -- Portage Unit Test functionality
# Copyright 2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$
import os
import sys
import time
import unittest
def main():
TEST_FILE = '__test__'
suite = unittest.TestSuite()
basedir = os.path.dirname(__file__)
testDirs = []
# the os.walk help mentions relative paths as being quirky
# I was tired of adding dirs to the list, so now we add __test__
# to each dir we want tested.
for root, dirs, files in os.walk(os.getcwd()):
if ".svn" in dirs:
dirs.remove('.svn')
if TEST_FILE in files:
testDirs.append(root)
for mydir in testDirs:
suite.addTests(getTests(os.path.join(basedir, mydir), basedir) )
return TextTestRunner(verbosity=2).run(suite)
def my_import(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
def getTests(path, base_path):
"""
path is the path to a given subdir ( 'portage/' for example)
This does a simple filter on files in that dir to give us modules
to import
"""
files = os.listdir(path)
files = [ f[:-3] for f in files if f.startswith("test") and f.endswith(".py") ]
parent_path = path[len(base_path)+1:]
parent_module = ".".join(("portage", "tests", parent_path))
parent_module = parent_module.replace('/', '.')
result = []
for mymodule in files:
# Make the trailing / a . for module importing
modname = ".".join((parent_module, mymodule))
mod = my_import(modname)
result.append(unittest.TestLoader().loadTestsFromModule(mod))
return result
class TextTestResult(unittest._TextTestResult):
"""
We need a subclass of unittest._TextTestResult to handle tests with TODO
This just adds an addTodo method that can be used to add tests
that are marked TODO; these can be displayed later
by the test runner.
"""
def __init__(self, stream, descriptions, verbosity):
unittest._TextTestResult.__init__( self, stream, descriptions, verbosity )
self.todoed = []
def addTodo(self, test, info):
self.todoed.append((test,info))
if self.showAll:
self.stream.writeln("TODO")
elif self.dots:
self.stream.write(".")
def printErrors(self):
if self.dots or self.showAll:
self.stream.writeln()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
self.printErrorList('TODO', self.todoed)
class TestCase(unittest.TestCase):
"""
We need a way to mark a unit test as "ok to fail"
This way someone can add a broken test and mark it as failed
and then fix the code later. This may not be a great approach
(broken code!!??!11oneone) but it does happen at times.
"""
def __init__(self, methodName='runTest'):
# This method exists because unittest.py in python 2.4 stores
# the methodName as __testMethodName while 2.5 uses
# _testMethodName.
self._testMethodName = methodName
unittest.TestCase.__init__(self, methodName)
self.todo = False
def defaultTestResult(self):
return TextTestResult()
def run(self, result=None):
if result is None: result = self.defaultTestResult()
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
try:
try:
self.setUp()
except KeyboardInterrupt:
raise
except:
result.addError(self, sys.exc_info())
return
ok = False
try:
testMethod()
ok = True
except self.failureException:
if self.todo:
result.addTodo(self,"%s: TODO" % testMethod)
else:
result.addFailure(self, sys.exc_info())
except (KeyboardInterrupt, SystemExit):
raise
except:
result.addError(self, sys.exc_info())
try:
self.tearDown()
except KeyboardInterrupt:
raise
except:
result.addError(self, sys.exc_info())
ok = False
if ok: result.addSuccess(self)
finally:
result.stopTest(self)
class TextTestRunner(unittest.TextTestRunner):
"""
We subclass unittest.TextTestRunner to output SKIP for tests that fail but are skippable
"""
def _makeResult(self):
return TextTestResult(self.stream, self.descriptions, self.verbosity)
def run(self, test):
"""
Run the given test case or test suite.
"""
result = self._makeResult()
startTime = time.time()
test(result)
stopTime = time.time()
timeTaken = stopTime - startTime
result.printErrors()
self.stream.writeln(result.separator2)
run = result.testsRun
self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run != 1 and "s" or "", timeTaken))
self.stream.writeln()
if not result.wasSuccessful():
self.stream.write("FAILED (")
failed, errored = map(len, (result.failures, result.errors))
if failed:
self.stream.write("failures=%d" % failed)
if errored:
if failed: self.stream.write(", ")
self.stream.write("errors=%d" % errored)
self.stream.writeln(")")
else:
self.stream.writeln("OK")
return result
test_cps = ['sys-apps/portage','virtual/portage']
test_versions = ['1.0', '1.0-r1','2.3_p4','1.0_alpha57']
test_slots = [ None, '1','gentoo-sources-2.6.17','spankywashere']
test_usedeps = ['foo','-bar', ('foo','bar'),
('foo','-bar'), ('foo?', '!bar?') ]