1bb99afd2800daecda16cc20d3974eae7c4fdd4b5Tobias Grosser#!/usr/bin/python
277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines#
3a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines# Copyright 2010-2012 Google Inc. All Rights Reserved.
477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
5a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines"""Renderscript Compiler Test.
677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
7a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen HinesRuns subdirectories of tests for the Renderscript compiler.
877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines"""
977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
1077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport filecmp
1177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport glob
1277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport os
13a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hinesimport re
1477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport shutil
1577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport subprocess
1677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesimport sys
1777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
1877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines__author__ = 'Android'
1977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
2077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
2177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesclass Options(object):
2277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  def __init__(self):
2388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    return
2477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  verbose = 0
2588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  cleanup = 1
26a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  updateCTS = 0
2777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
2877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
29a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hinesdef CompareFiles(actual, expect):
30a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  """Compares actual and expect for equality."""
31dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  if not os.path.isfile(actual):
32dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    if Options.verbose:
33dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'Could not find %s' % actual
34dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    return False
35dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  if not os.path.isfile(expect):
36dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    if Options.verbose:
37dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'Could not find %s' % expect
38dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    return False
39dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
4077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  return filecmp.cmp(actual, expect, False)
4177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
4277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
43a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hinesdef UpdateFiles(src, dst):
44a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  """Update dst if it is different from src."""
45a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if not CompareFiles(src, dst):
46a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    print 'Copying from %s to %s' % (src, dst)
47a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    shutil.copyfile(src, dst)
48a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines
49a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines
500b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hinesdef GetCommandLineArgs(filename):
51a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  """Extracts command line arguments from first comment line in a file."""
520b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  f = open(filename, 'r')
530b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  line = f.readline()
540b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  if line[0] == '/' and line [1] == '/':
55a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    return line[2:].strip()
560b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  else:
57a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    return ''
580b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
590b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
6077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesdef ExecTest(dirname):
6177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  """Executes an llvm-rs-cc test from dirname."""
6277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  passed = True
6377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
6477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  if Options.verbose != 0:
6577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    print 'Testing %s' % dirname
6677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
6777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  os.chdir(dirname)
68dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stdout_file = open('stdout.txt', 'w+')
69dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stderr_file = open('stderr.txt', 'w+')
7077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
7177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  cmd_string = ('../../../../../out/host/linux-x86/bin/llvm-rs-cc '
7277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines                '-o tmp/ -p tmp/ '
73c632be206ac4fe49a5db05cfa54942d774329dbeStephen Hines                '-MD '
74ca13d7cc4c71ef5426e16bc997d4640facf7eda4Stephen Hines                '-I ../../../../../frameworks/rs/scriptc/ '
754470828373378510f1d02cae4e80cfe143577de6Stephen Hines                '-I ../../../../../external/clang/lib/Headers/')
7677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  base_args = cmd_string.split()
7777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  rs_files = glob.glob('*.rs')
7811274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines  fs_files = glob.glob('*.fs')
7911274a7324b478ec13e1d10a1b81350b34a65ab1Stephen Hines  rs_files += fs_files;
808dd522d2a6b96c79117bdc5d6b58d336846e4346Stephen Hines  rs_files.sort()
810b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
820b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # Extra command line arguments can be placed as // comments at the start of
830b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # any .rs file. We automatically bundle up all of these extra args and invoke
840b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # llvm-rs-cc with them.
85a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  extra_args_str = ''
860b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  for rs_file in rs_files:
870b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines    extra_args_str += GetCommandLineArgs(rs_file)
880b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  extra_args = extra_args_str.split()
890b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
900b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  args = base_args + extra_args + rs_files
9177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
92e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  if Options.verbose > 1:
93e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print 'Executing:',
94e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for arg in args:
95e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      print arg,
96e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print
97e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines
9877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # Execute the command and check the resulting shell return value.
9977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # All tests that are expected to FAIL have directory names that
10077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # start with 'F_'. Other tests that are expected to PASS have
10177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # directory names that start with 'P_'.
1026b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  ret = 0
1036b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  try:
1046b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    ret = subprocess.call(args, stdout=stdout_file, stderr=stderr_file)
1056b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  except:
1066b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    passed = False
1076b201eb3306b9609a991728a52ce948974bd4aedStephen Hines
108dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stdout_file.flush()
109dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stderr_file.flush()
110dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
111dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  if Options.verbose > 1:
112dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    stdout_file.seek(0)
113dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    stderr_file.seek(0)
114dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    for line in stdout_file:
115dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'STDOUT>', line,
116dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    for line in stderr_file:
117dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'STDERR>', line,
118dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
119dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stdout_file.close()
120dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stderr_file.close()
121dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
12277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  if dirname[0:2] == 'F_':
12377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if ret == 0:
12477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      passed = False
12577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if Options.verbose:
12677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        print 'Command passed on invalid input'
12777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  elif dirname[0:2] == 'P_':
12877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if ret != 0:
12977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      passed = False
13077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if Options.verbose:
13177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        print 'Command failed on valid input'
13277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  else:
133e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    passed = (ret == 0)
13477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
13577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'Test Directory name should start with an F or a P'
13677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
137a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if not CompareFiles('stdout.txt', 'stdout.txt.expect'):
13877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    passed = False
13977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
14077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'stdout is different'
141a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if not CompareFiles('stderr.txt', 'stderr.txt.expect'):
14277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    passed = False
14377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
14477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'stderr is different'
14577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
146a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if Options.updateCTS:
147a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    # Copy resulting files to appropriate CTS directory (if different).
148a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    if passed and glob.glob('IN_CTS'):
149a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_path = '../../../../../cts/'
150a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_res_raw_path = cts_path + 'tests/res/raw/'
151a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_src_path = cts_path + 'tests/tests/renderscript/src/'
152a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      for bc_src in glob.glob('tmp/*.bc'):
153a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        bc_dst = re.sub('tmp\/', cts_res_raw_path, bc_src, 1)
154a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        UpdateFiles(bc_src, bc_dst)
155a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      for java_src in glob.glob('tmp/android/renderscript/cts/*.java'):
156a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        java_dst = re.sub('tmp\/', cts_src_path, java_src, 1)
157a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        UpdateFiles(java_src, java_dst)
158a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines
15988bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  if Options.cleanup:
1606b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    try:
1616b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      os.remove('stdout.txt')
1626b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      os.remove('stderr.txt')
1636b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      shutil.rmtree('tmp/')
1646b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    except:
1656b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      pass
16677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
16777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  os.chdir('..')
16877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  return passed
16977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
17077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
17188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hinesdef Usage():
172a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  """Print out usage information."""
17388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  print ('Usage: %s [OPTION]... [TESTNAME]...'
174a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines         'Renderscript Compiler Test Harness\n'
17588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         'Runs TESTNAMEs (all tests by default)\n'
17688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         'Available Options:\n'
17788bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         '  -h, --help          Help message\n'
17888bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         '  -n, --no-cleanup    Don\'t clean up after running tests\n'
179a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines         '  -u, --update-cts    Update CTS test versions\n'
180cad0d742e189196221fb028f8501f5ca26617723Jean-Luc Brouillet         '  -v, --verbose       Verbose output.  Enter multiple -v to get more verbose.\n'
18188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        ) % (sys.argv[0]),
18288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  return
18388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
18488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
18577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesdef main():
18677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  passed = 0
18777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  failed = 0
18888bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  files = []
189e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  failed_tests = []
19077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
19177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  for arg in sys.argv[1:]:
19288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    if arg in ('-h', '--help'):
19388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      Usage()
19488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      return 0
19588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    elif arg in ('-n', '--no-cleanup'):
19688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      Options.cleanup = 0
197a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    elif arg in ('-u', '--update-cts'):
198a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      Options.updateCTS = 1
19988bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    elif arg in ('-v', '--verbose'):
200e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      Options.verbose += 1
20177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    else:
20288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      # Test list to run
20388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      if os.path.isdir(arg):
20488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        files.append(arg)
20588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      else:
20688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        print >> sys.stderr, 'Invalid test or option: %s' % arg
20788bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        return 1
20888bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
20988bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  if not files:
210e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    tmp_files = os.listdir('.')
211e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    # Only run tests that are known to PASS or FAIL
212e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    # Disabled tests can be marked D_ and invoked explicitly
213e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for f in tmp_files:
214e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      if os.path.isdir(f) and (f[0:2] == 'F_' or f[0:2] == 'P_'):
215e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines        files.append(f)
21677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
21777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  for f in files:
21877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if os.path.isdir(f):
21977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if ExecTest(f):
22077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        passed += 1
22177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      else:
22277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        failed += 1
223e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines        failed_tests.append(f)
22477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
22577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  print 'Tests Passed: %d\n' % passed,
22677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  print 'Tests Failed: %d\n' % failed,
227e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  if failed:
228e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print 'Failures:',
229e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for t in failed_tests:
230e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      print t,
23177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  return failed != 0
23377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesif __name__ == '__main__':
23677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  sys.exit(main())
237