blob: 5d8c7dbfd453c7f146f13aad7848c831003c3c94 [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import multiprocessing
import sys
from .cover import CoverageContext
from . import handle_list, handle_debug, handle_train, handle_test
from .pipeline import result_loop
HANDLERS = {
'list': handle_list.ListHandler,
'debug': handle_debug.DebugHandler,
'train': handle_train.TrainHandler,
'test': handle_test.TestHandler,
}
def _parse_args(args):
args = args or sys.argv[1:]
# Set the default mode if not specified and not passing --help
search_names = set(HANDLERS.keys() + ['-h', '--help'])
if not any(arg in search_names for arg in args):
args.insert(0, 'test')
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(
title='Mode (default "test")', dest='mode',
help='See `[mode] --help` for more options.')
for k, h in HANDLERS.iteritems():
doc = h.__doc__
if doc:
doc = doc[0].lower() + doc[1:]
sp = subparsers.add_parser(k, help=doc)
h.add_options(sp)
mg = sp.add_mutually_exclusive_group()
mg.add_argument(
'--quiet', action='store_true',
help='be quiet (only print failures)')
mg.add_argument(
'--verbose', action='store_true', help='be verbose')
if not h.SKIP_RUNLOOP:
sp.add_argument(
'--jobs', metavar='N', type=int,
default=multiprocessing.cpu_count(),
help='run N jobs in parallel (default %(default)s)')
sp.add_argument(
'--test_list', metavar='FILE',
help='take the list of test globs from the FILE (use "-" for stdin)')
sp.add_argument(
'test_glob', nargs='*', help=(
'glob to filter the tests acted on. If the glob begins with "-" '
'then it acts as a negation glob and anything which matches it '
'will be skipped. If a glob doesn\'t have "*" in it, "*" will be '
'implicitly appended to the end'))
opts = parser.parse_args(args)
if not hasattr(opts, 'jobs'):
opts.jobs = 0
elif opts.jobs < 1:
parser.error('--jobs was less than 1')
if opts.test_list:
fh = sys.stdin if opts.test_list == '-' else open(opts.test_list, 'rb')
with fh as tl:
opts.test_glob += [l.strip() for l in tl.readlines()]
opts.handler = HANDLERS[opts.mode]
del opts.test_list
del opts.mode
return opts
def main(name, test_gen, coverage_includes=None, coverage_omits=None,
args=None):
"""Entry point for tests using expect_tests.
Example:
import expect_tests
def happy_fn(val):
# Usually you would return data which is the result of some deterministic
# computation.
return expect_tests.Result({'neet': '%s string value' % val})
def Gen():
yield expect_tests.Test('happy', happy_fn, args=('happy',))
if __name__ == '__main__':
expect_tests.main('happy_test_suite', Gen)
@param name: Name of the test suite.
@param test_gen: A Generator which yields Test objects.
@param coverage_includes: A list of path globs to include under coverage.
@param coverage_omits: A list of path globs to exclude under coverage.
@param args: Commandline args (starting at argv[1])
"""
try:
opts = _parse_args(args)
cover_ctx = CoverageContext(name, coverage_includes, coverage_omits,
not opts.handler.SKIP_RUNLOOP)
error, killed = result_loop(test_gen, cover_ctx.create_subprocess_context(),
opts)
cover_ctx.cleanup()
if not killed and not opts.test_glob:
if not cover_ctx.report(opts.verbose):
sys.exit(2)
sys.exit(error or killed)
except KeyboardInterrupt:
pass