initial import
[vuplus_webkit] / Source / ThirdParty / gyp / gyptest.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2009 Google Inc. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 __doc__ = """
8 gyptest.py -- test runner for GYP tests.
9 """
10
11 import os
12 import optparse
13 import subprocess
14 import sys
15
16 class CommandRunner:
17   """
18   Executor class for commands, including "commands" implemented by
19   Python functions.
20   """
21   verbose = True
22   active = True
23
24   def __init__(self, dictionary={}):
25     self.subst_dictionary(dictionary)
26
27   def subst_dictionary(self, dictionary):
28     self._subst_dictionary = dictionary
29
30   def subst(self, string, dictionary=None):
31     """
32     Substitutes (via the format operator) the values in the specified
33     dictionary into the specified command.
34
35     The command can be an (action, string) tuple.  In all cases, we
36     perform substitution on strings and don't worry if something isn't
37     a string.  (It's probably a Python function to be executed.)
38     """
39     if dictionary is None:
40       dictionary = self._subst_dictionary
41     if dictionary:
42       try:
43         string = string % dictionary
44       except TypeError:
45         pass
46     return string
47
48   def display(self, command, stdout=None, stderr=None):
49     if not self.verbose:
50       return
51     if type(command) == type(()):
52       func = command[0]
53       args = command[1:]
54       s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
55     if type(command) == type([]):
56       # TODO:  quote arguments containing spaces
57       # TODO:  handle meta characters?
58       s = ' '.join(command)
59     else:
60       s = self.subst(command)
61     if not s.endswith('\n'):
62       s += '\n'
63     sys.stdout.write(s)
64     sys.stdout.flush()
65
66   def execute(self, command, stdout=None, stderr=None):
67     """
68     Executes a single command.
69     """
70     if not self.active:
71       return 0
72     if type(command) == type(''):
73       command = self.subst(command)
74       cmdargs = shlex.split(command)
75       if cmdargs[0] == 'cd':
76          command = (os.chdir,) + tuple(cmdargs[1:])
77     if type(command) == type(()):
78       func = command[0]
79       args = command[1:]
80       return func(*args)
81     else:
82       if stdout is sys.stdout:
83         # Same as passing sys.stdout, except python2.4 doesn't fail on it.
84         subout = None
85       else:
86         # Open pipe for anything else so Popen works on python2.4.
87         subout = subprocess.PIPE
88       if stderr is sys.stderr:
89         # Same as passing sys.stderr, except python2.4 doesn't fail on it.
90         suberr = None
91       elif stderr is None:
92         # Merge with stdout if stderr isn't specified.
93         suberr = subprocess.STDOUT
94       else:
95         # Open pipe for anything else so Popen works on python2.4.
96         suberr = subprocess.PIPE
97       p = subprocess.Popen(command,
98                            shell=(sys.platform == 'win32'),
99                            stdout=subout,
100                            stderr=suberr)
101       p.wait()
102       if stdout is None:
103         self.stdout = p.stdout.read()
104       elif stdout is not sys.stdout:
105         stdout.write(p.stdout.read())
106       if stderr not in (None, sys.stderr):
107         stderr.write(p.stderr.read())
108       return p.returncode
109
110   def run(self, command, display=None, stdout=None, stderr=None):
111     """
112     Runs a single command, displaying it first.
113     """
114     if display is None:
115       display = command
116     self.display(display)
117     return self.execute(command, stdout, stderr)
118
119
120 class Unbuffered:
121   def __init__(self, fp):
122     self.fp = fp
123   def write(self, arg):
124     self.fp.write(arg)
125     self.fp.flush()
126   def __getattr__(self, attr):
127     return getattr(self.fp, attr)
128
129 sys.stdout = Unbuffered(sys.stdout)
130 sys.stderr = Unbuffered(sys.stderr)
131
132
133 def find_all_gyptest_files(directory):
134     result = []
135     for root, dirs, files in os.walk(directory):
136       if '.svn' in dirs:
137         dirs.remove('.svn')
138       result.extend([ os.path.join(root, f) for f in files
139                      if f.startswith('gyptest') and f.endswith('.py') ])
140     result.sort()
141     return result
142
143
144 def main(argv=None):
145   if argv is None:
146     argv = sys.argv
147
148   usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
149   parser = optparse.OptionParser(usage=usage)
150   parser.add_option("-a", "--all", action="store_true",
151             help="run all tests")
152   parser.add_option("-C", "--chdir", action="store", default=None,
153             help="chdir to the specified directory")
154   parser.add_option("-f", "--format", action="store", default='',
155             help="run tests with the specified formats")
156   parser.add_option("-l", "--list", action="store_true",
157             help="list available tests and exit")
158   parser.add_option("-n", "--no-exec", action="store_true",
159             help="no execute, just print the command line")
160   parser.add_option("--passed", action="store_true",
161             help="report passed tests")
162   parser.add_option("--path", action="append", default=[],
163             help="additional $PATH directory")
164   parser.add_option("-q", "--quiet", action="store_true",
165             help="quiet, don't print test command lines")
166   opts, args = parser.parse_args(argv[1:])
167
168   if opts.chdir:
169     os.chdir(opts.chdir)
170
171   if opts.path:
172     os.environ['PATH'] += ':' + ':'.join(opts.path)
173
174   if not args:
175     if not opts.all:
176       sys.stderr.write('Specify -a to get all tests.\n')
177       return 1
178     args = ['test']
179
180   tests = []
181   for arg in args:
182     if os.path.isdir(arg):
183       tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
184     else:
185       tests.append(arg)
186
187   if opts.list:
188     for test in tests:
189       print test
190     sys.exit(0)
191
192   CommandRunner.verbose = not opts.quiet
193   CommandRunner.active = not opts.no_exec
194   cr = CommandRunner()
195
196   os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
197   if not opts.quiet:
198     sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
199
200   passed = []
201   failed = []
202   no_result = []
203
204   if opts.format:
205     format_list = opts.format.split(',')
206   else:
207     # TODO:  not duplicate this mapping from pylib/gyp/__init__.py
208     format_list = [ {
209       'freebsd7': 'make',
210       'freebsd8': 'make',
211       'cygwin':   'msvs',
212       'win32':    'msvs',
213       'linux2':   'make',
214       'darwin':   'xcode',
215     }[sys.platform] ]
216
217   for format in format_list:
218     os.environ['TESTGYP_FORMAT'] = format
219     if not opts.quiet:
220       sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
221
222     for test in tests:
223       status = cr.run([sys.executable, test],
224                       stdout=sys.stdout,
225                       stderr=sys.stderr)
226       if status == 2:
227         no_result.append(test)
228       elif status:
229         failed.append(test)
230       else:
231         passed.append(test)
232
233   if not opts.quiet:
234     def report(description, tests):
235       if tests:
236         if len(tests) == 1:
237           sys.stdout.write("\n%s the following test:\n" % description)
238         else:
239           fmt = "\n%s the following %d tests:\n"
240           sys.stdout.write(fmt % (description, len(tests)))
241         sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
242
243     if opts.passed:
244       report("Passed", passed)
245     report("Failed", failed)
246     report("No result from", no_result)
247
248   if failed:
249     return 1
250   else:
251     return 0
252
253
254 if __name__ == "__main__":
255   sys.exit(main())