blob: 248ccf11864a2b2a084250afd1e7da8cbef57556 [file] [log] [blame]
#!/usr/bin/env python
"""Test runner.
For further help, enter this at a command prompt:
python test.py --help
"""
import cgitb
#cgitb.enable(format="text")
# Modules containing tests to run -- a test is anything named *Tests, which
# should be classes deriving from unittest.TestCase.
MODULE_NAMES = ["test_date", "test_browser", "test_response", "test_cookies",
"test_headers", "test_urllib2", "test_pullparser",
"test_useragent", "test_html", "test_opener",
]
import sys, os, traceback, logging, glob
from unittest import defaultTestLoader, TextTestRunner, TestSuite, TestCase, \
_TextTestResult
#level = logging.DEBUG
#level = logging.INFO
#level = logging.WARNING
#level = logging.NOTSET
#logging.getLogger("mechanize").setLevel(level)
#logging.getLogger("mechanize").addHandler(logging.StreamHandler(sys.stdout))
class CgitbTextResult(_TextTestResult):
def _exc_info_to_string(self, err, test):
"""Converts a sys.exc_info()-style tuple of values into a string."""
exctype, value, tb = err
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
if exctype is test.failureException:
# Skip assert*() traceback levels
length = self._count_relevant_tb_levels(tb)
return cgitb.text((exctype, value, tb))
return cgitb.text((exctype, value, tb))
class CgitbTextTestRunner(TextTestRunner):
def _makeResult(self):
return CgitbTextResult(self.stream, self.descriptions, self.verbosity)
class TestProgram:
"""A command-line program that runs a set of tests; this is primarily
for making test modules conveniently executable.
"""
USAGE = """\
Usage: %(progName)s [options] [test] [...]
Options:
-h, --help Show this message
-v, --verbose Verbose output
-q, --quiet Minimal output
Examples:
%(progName)s - run default set of tests
%(progName)s MyTestSuite - run suite 'MyTestSuite'
%(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
%(progName)s MyTestCase - run all 'test*' test methods
in MyTestCase
"""
def __init__(self, moduleNames, defaultTest=None,
argv=None, testRunner=None, testLoader=defaultTestLoader):
self.modules = []
for moduleName in moduleNames:
module = __import__(moduleName)
for part in moduleName.split('.')[1:]:
module = getattr(module, part)
self.modules.append(module)
if argv is None:
argv = sys.argv
self.verbosity = 1
self.defaultTest = defaultTest
self.testRunner = testRunner
self.testLoader = testLoader
self.progName = os.path.basename(argv[0])
self.parseArgs(argv)
def usageExit(self, msg=None):
if msg: print msg
print self.USAGE % self.__dict__
sys.exit(2)
def parseArgs(self, argv):
import getopt
try:
options, args = getopt.getopt(argv[1:], 'hHvq',
['help','verbose','quiet'])
for opt, value in options:
if opt in ('-h','-H','--help'):
self.usageExit()
if opt in ('-q','--quiet'):
self.verbosity = 0
if opt in ('-v','--verbose'):
self.verbosity = 2
if len(args) == 0 and self.defaultTest is None:
suite = TestSuite()
for module in self.modules:
test = self.testLoader.loadTestsFromModule(module)
suite.addTest(test)
self.test = suite
return
if len(args) > 0:
self.testNames = args
else:
self.testNames = (self.defaultTest,)
self.createTests()
except getopt.error, msg:
self.usageExit(msg)
def createTests(self):
self.test = self.testLoader.loadTestsFromNames(self.testNames)
def runTests(self):
if self.testRunner is None:
self.testRunner = TextTestRunner(verbosity=self.verbosity)
result = self.testRunner.run(self.test)
return result
if __name__ == "__main__":
## sys.path.insert(0, '/home/john/comp/dev/rl/jjlee/lib/python')
## import jjl
## import __builtin__
## __builtin__.jjl = jjl
# XXX temporary stop-gap to run doctests
# XXXX coverage output seems incorrect ATM
run_coverage = "-c" in sys.argv
if run_coverage:
sys.argv.remove("-c")
use_cgitb = "-t" in sys.argv
if use_cgitb:
sys.argv.remove("-t")
run_doctests = "-d" not in sys.argv
if not run_doctests:
sys.argv.remove("-d")
# import local copy of Python 2.5 doctest
assert os.path.isdir("test")
sys.path.insert(0, "test")
# needed for recent doctest / linecache -- this is only for testing
# purposes, these don't get installed
# doctest.py revision 45701 and linecache.py revision 45940. Since
# linecache is used by Python itself, linecache.py is renamed
# linecache_copy.py, and this copy of doctest is modified (only) to use
# that renamed module.
sys.path.insert(0, "test-tools")
import doctest
import coverage
if run_coverage:
print 'running coverage'
coverage.erase()
coverage.start()
import mechanize
if run_doctests:
# run .doctest files needing special support
common_globs = {"mechanize": mechanize}
pm_doctest_filename = os.path.join("test", "test_password_manager.doctest")
for globs in [
{"mgr_class": mechanize.HTTPPasswordMgr},
{"mgr_class": mechanize.HTTPProxyPasswordMgr},
]:
globs.update(common_globs)
doctest.testfile(
pm_doctest_filename,
#os.path.join("test", "test_scratch.doctest"),
globs=globs,
)
# run .doctest files
special_doctests = [pm_doctest_filename,
os.path.join("test", "test_scratch.doctest"),
]
doctest_files = glob.glob(os.path.join("test", "*.doctest"))
for dt in special_doctests:
if dt in doctest_files:
doctest_files.remove(dt)
for df in doctest_files:
doctest.testfile(df)
# run doctests in docstrings
from mechanize import _headersutil, _auth, _clientcookie, _pullparser, \
_http, _rfc3986
doctest.testmod(_headersutil)
doctest.testmod(_rfc3986)
doctest.testmod(_auth)
doctest.testmod(_clientcookie)
doctest.testmod(_pullparser)
doctest.testmod(_http)
# run vanilla unittest tests
import unittest
test_path = os.path.join(os.path.dirname(sys.argv[0]), "test")
sys.path.insert(0, test_path)
test_runner = None
if use_cgitb:
test_runner = CgitbTextTestRunner()
prog = TestProgram(MODULE_NAMES, testRunner=test_runner)
result = prog.runTests()
if run_coverage:
# HTML coverage report
import colorize
try:
os.mkdir("coverage")
except OSError:
pass
private_modules = glob.glob("mechanize/_*.py")
private_modules.remove("mechanize/__init__.py")
for module_filename in private_modules:
module_name = module_filename.replace("/", ".")[:-3]
print module_name
module = sys.modules[module_name]
f, s, m, mf = coverage.analysis(module)
fo = open(os.path.join('coverage', os.path.basename(f)+'.html'), 'wb')
colorize.colorize_file(f, outstream=fo, not_covered=mf)
fo.close()
coverage.report(module)
#print coverage.analysis(module)
# XXX exit status is wrong -- does not take account of doctests
sys.exit(not result.wasSuccessful())