123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- #!/usr/bin/env python
- # Copyright (c) 2012 Google Inc. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- __doc__ = """
- gyptest.py -- test runner for GYP tests.
- """
- import os
- import optparse
- import subprocess
- import sys
- class CommandRunner:
- """
- Executor class for commands, including "commands" implemented by
- Python functions.
- """
- verbose = True
- active = True
- def __init__(self, dictionary={}):
- self.subst_dictionary(dictionary)
- def subst_dictionary(self, dictionary):
- self._subst_dictionary = dictionary
- def subst(self, string, dictionary=None):
- """
- Substitutes (via the format operator) the values in the specified
- dictionary into the specified command.
- The command can be an (action, string) tuple. In all cases, we
- perform substitution on strings and don't worry if something isn't
- a string. (It's probably a Python function to be executed.)
- """
- if dictionary is None:
- dictionary = self._subst_dictionary
- if dictionary:
- try:
- string = string % dictionary
- except TypeError:
- pass
- return string
- def display(self, command, stdout=None, stderr=None):
- if not self.verbose:
- return
- if type(command) == type(()):
- func = command[0]
- args = command[1:]
- s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
- if type(command) == type([]):
- # TODO: quote arguments containing spaces
- # TODO: handle meta characters?
- s = ' '.join(command)
- else:
- s = self.subst(command)
- if not s.endswith('\n'):
- s += '\n'
- sys.stdout.write(s)
- sys.stdout.flush()
- def execute(self, command, stdout=None, stderr=None):
- """
- Executes a single command.
- """
- if not self.active:
- return 0
- if type(command) == type(''):
- command = self.subst(command)
- cmdargs = shlex.split(command)
- if cmdargs[0] == 'cd':
- command = (os.chdir,) + tuple(cmdargs[1:])
- if type(command) == type(()):
- func = command[0]
- args = command[1:]
- return func(*args)
- else:
- if stdout is sys.stdout:
- # Same as passing sys.stdout, except python2.4 doesn't fail on it.
- subout = None
- else:
- # Open pipe for anything else so Popen works on python2.4.
- subout = subprocess.PIPE
- if stderr is sys.stderr:
- # Same as passing sys.stderr, except python2.4 doesn't fail on it.
- suberr = None
- elif stderr is None:
- # Merge with stdout if stderr isn't specified.
- suberr = subprocess.STDOUT
- else:
- # Open pipe for anything else so Popen works on python2.4.
- suberr = subprocess.PIPE
- p = subprocess.Popen(command,
- shell=(sys.platform == 'win32'),
- stdout=subout,
- stderr=suberr)
- p.wait()
- if stdout is None:
- self.stdout = p.stdout.read()
- elif stdout is not sys.stdout:
- stdout.write(p.stdout.read())
- if stderr not in (None, sys.stderr):
- stderr.write(p.stderr.read())
- return p.returncode
- def run(self, command, display=None, stdout=None, stderr=None):
- """
- Runs a single command, displaying it first.
- """
- if display is None:
- display = command
- self.display(display)
- return self.execute(command, stdout, stderr)
- class Unbuffered:
- def __init__(self, fp):
- self.fp = fp
- def write(self, arg):
- self.fp.write(arg)
- self.fp.flush()
- def __getattr__(self, attr):
- return getattr(self.fp, attr)
- sys.stdout = Unbuffered(sys.stdout)
- sys.stderr = Unbuffered(sys.stderr)
- def is_test_name(f):
- return f.startswith('gyptest') and f.endswith('.py')
- def find_all_gyptest_files(directory):
- result = []
- for root, dirs, files in os.walk(directory):
- if '.svn' in dirs:
- dirs.remove('.svn')
- result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ])
- result.sort()
- return result
- def main(argv=None):
- if argv is None:
- argv = sys.argv
- usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
- parser = optparse.OptionParser(usage=usage)
- parser.add_option("-a", "--all", action="store_true",
- help="run all tests")
- parser.add_option("-C", "--chdir", action="store", default=None,
- help="chdir to the specified directory")
- parser.add_option("-f", "--format", action="store", default='',
- help="run tests with the specified formats")
- parser.add_option("-G", '--gyp_option', action="append", default=[],
- help="Add -G options to the gyp command line")
- parser.add_option("-l", "--list", action="store_true",
- help="list available tests and exit")
- parser.add_option("-n", "--no-exec", action="store_true",
- help="no execute, just print the command line")
- parser.add_option("--passed", action="store_true",
- help="report passed tests")
- parser.add_option("--path", action="append", default=[],
- help="additional $PATH directory")
- parser.add_option("-q", "--quiet", action="store_true",
- help="quiet, don't print test command lines")
- opts, args = parser.parse_args(argv[1:])
- if opts.chdir:
- os.chdir(opts.chdir)
- if opts.path:
- extra_path = [os.path.abspath(p) for p in opts.path]
- extra_path = os.pathsep.join(extra_path)
- os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH']
- if not args:
- if not opts.all:
- sys.stderr.write('Specify -a to get all tests.\n')
- return 1
- args = ['test']
- tests = []
- for arg in args:
- if os.path.isdir(arg):
- tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
- else:
- if not is_test_name(os.path.basename(arg)):
- print >>sys.stderr, arg, 'is not a valid gyp test name.'
- sys.exit(1)
- tests.append(arg)
- if opts.list:
- for test in tests:
- print test
- sys.exit(0)
- CommandRunner.verbose = not opts.quiet
- CommandRunner.active = not opts.no_exec
- cr = CommandRunner()
- os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
- if not opts.quiet:
- sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
- passed = []
- failed = []
- no_result = []
- if opts.format:
- format_list = opts.format.split(',')
- else:
- # TODO: not duplicate this mapping from pylib/gyp/__init__.py
- format_list = {
- 'aix5': ['make'],
- 'freebsd7': ['make'],
- 'freebsd8': ['make'],
- 'openbsd5': ['make'],
- 'cygwin': ['msvs'],
- 'win32': ['msvs', 'ninja'],
- 'linux2': ['make', 'ninja'],
- 'linux3': ['make', 'ninja'],
- 'darwin': ['make', 'ninja', 'xcode'],
- }[sys.platform]
- for format in format_list:
- os.environ['TESTGYP_FORMAT'] = format
- if not opts.quiet:
- sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
- gyp_options = []
- for option in opts.gyp_option:
- gyp_options += ['-G', option]
- if gyp_options and not opts.quiet:
- sys.stdout.write('Extra Gyp options: %s\n' % gyp_options)
- for test in tests:
- status = cr.run([sys.executable, test] + gyp_options,
- stdout=sys.stdout,
- stderr=sys.stderr)
- if status == 2:
- no_result.append(test)
- elif status:
- failed.append(test)
- else:
- passed.append(test)
- if not opts.quiet:
- def report(description, tests):
- if tests:
- if len(tests) == 1:
- sys.stdout.write("\n%s the following test:\n" % description)
- else:
- fmt = "\n%s the following %d tests:\n"
- sys.stdout.write(fmt % (description, len(tests)))
- sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
- if opts.passed:
- report("Passed", passed)
- report("Failed", failed)
- report("No result from", no_result)
- if failed:
- return 1
- else:
- return 0
- if __name__ == "__main__":
- sys.exit(main())
|