177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines#!/usr/bin/python2.4
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')
788dd522d2a6b96c79117bdc5d6b58d336846e4346Stephen Hines  rs_files.sort()
790b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
800b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # Extra command line arguments can be placed as // comments at the start of
810b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # any .rs file. We automatically bundle up all of these extra args and invoke
820b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  # llvm-rs-cc with them.
83a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  extra_args_str = ''
840b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  for rs_file in rs_files:
850b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines    extra_args_str += GetCommandLineArgs(rs_file)
860b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  extra_args = extra_args_str.split()
870b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines
880b874dacc570d6ed42cad26e0907548d459dfde5Stephen Hines  args = base_args + extra_args + rs_files
8977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
90e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  if Options.verbose > 1:
91e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print 'Executing:',
92e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for arg in args:
93e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      print arg,
94e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print
95e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines
9677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # Execute the command and check the resulting shell return value.
9777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # All tests that are expected to FAIL have directory names that
9877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # start with 'F_'. Other tests that are expected to PASS have
9977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  # directory names that start with 'P_'.
1006b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  ret = 0
1016b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  try:
1026b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    ret = subprocess.call(args, stdout=stdout_file, stderr=stderr_file)
1036b201eb3306b9609a991728a52ce948974bd4aedStephen Hines  except:
1046b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    passed = False
1056b201eb3306b9609a991728a52ce948974bd4aedStephen Hines
106dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stdout_file.flush()
107dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stderr_file.flush()
108dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
109dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  if Options.verbose > 1:
110dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    stdout_file.seek(0)
111dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    stderr_file.seek(0)
112dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    for line in stdout_file:
113dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'STDOUT>', line,
114dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines    for line in stderr_file:
115dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines      print 'STDERR>', line,
116dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
117dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stdout_file.close()
118dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines  stderr_file.close()
119dd6206bb61bf8df2ed6b643abe8a29c48a315685Stephen Hines
12077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  if dirname[0:2] == 'F_':
12177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if ret == 0:
12277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      passed = False
12377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if Options.verbose:
12477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        print 'Command passed on invalid input'
12577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  elif dirname[0:2] == 'P_':
12677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if ret != 0:
12777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      passed = False
12877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if Options.verbose:
12977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        print 'Command failed on valid input'
13077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  else:
131e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    passed = (ret == 0)
13277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
13377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'Test Directory name should start with an F or a P'
13477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
135a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if not CompareFiles('stdout.txt', 'stdout.txt.expect'):
13677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    passed = False
13777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
13877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'stdout is different'
139a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if not CompareFiles('stderr.txt', 'stderr.txt.expect'):
14077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    passed = False
14177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if Options.verbose:
14277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      print 'stderr is different'
14377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
144a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  if Options.updateCTS:
145a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    # Copy resulting files to appropriate CTS directory (if different).
146a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    if passed and glob.glob('IN_CTS'):
147a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_path = '../../../../../cts/'
148a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_res_raw_path = cts_path + 'tests/res/raw/'
149a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      cts_src_path = cts_path + 'tests/tests/renderscript/src/'
150a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      for bc_src in glob.glob('tmp/*.bc'):
151a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        bc_dst = re.sub('tmp\/', cts_res_raw_path, bc_src, 1)
152a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        UpdateFiles(bc_src, bc_dst)
153a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      for java_src in glob.glob('tmp/android/renderscript/cts/*.java'):
154a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        java_dst = re.sub('tmp\/', cts_src_path, java_src, 1)
155a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines        UpdateFiles(java_src, java_dst)
156a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines
15788bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  if Options.cleanup:
1586b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    try:
1596b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      os.remove('stdout.txt')
1606b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      os.remove('stderr.txt')
1616b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      shutil.rmtree('tmp/')
1626b201eb3306b9609a991728a52ce948974bd4aedStephen Hines    except:
1636b201eb3306b9609a991728a52ce948974bd4aedStephen Hines      pass
16477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
16577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  os.chdir('..')
16677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  return passed
16777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
16877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
16988bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hinesdef Usage():
170a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines  """Print out usage information."""
17188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  print ('Usage: %s [OPTION]... [TESTNAME]...'
172a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines         'Renderscript Compiler Test Harness\n'
17388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         'Runs TESTNAMEs (all tests by default)\n'
17488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         'Available Options:\n'
17588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         '  -h, --help          Help message\n'
17688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         '  -n, --no-cleanup    Don\'t clean up after running tests\n'
177a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines         '  -u, --update-cts    Update CTS test versions\n'
17888bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines         '  -v, --verbose       Verbose output\n'
17988bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        ) % (sys.argv[0]),
18088bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  return
18188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
18288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
18377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesdef main():
18477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  passed = 0
18577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  failed = 0
18688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  files = []
187e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  failed_tests = []
18877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
18977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  for arg in sys.argv[1:]:
19088bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    if arg in ('-h', '--help'):
19188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      Usage()
19288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      return 0
19388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    elif arg in ('-n', '--no-cleanup'):
19488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      Options.cleanup = 0
195a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines    elif arg in ('-u', '--update-cts'):
196a4c54ee5ceb193d514618d341ec6967bff02cb2bStephen Hines      Options.updateCTS = 1
19788bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines    elif arg in ('-v', '--verbose'):
198e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      Options.verbose += 1
19977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    else:
20088bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      # Test list to run
20188bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      if os.path.isdir(arg):
20288bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        files.append(arg)
20388bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines      else:
20488bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        print >> sys.stderr, 'Invalid test or option: %s' % arg
20588bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines        return 1
20688bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines
20788bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines  if not files:
208e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    tmp_files = os.listdir('.')
209e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    # Only run tests that are known to PASS or FAIL
210e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    # Disabled tests can be marked D_ and invoked explicitly
211e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for f in tmp_files:
212e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      if os.path.isdir(f) and (f[0:2] == 'F_' or f[0:2] == 'P_'):
213e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines        files.append(f)
21477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
21577b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  for f in files:
21677b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines    if os.path.isdir(f):
21777b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      if ExecTest(f):
21877b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        passed += 1
21977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines      else:
22077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines        failed += 1
221e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines        failed_tests.append(f)
22277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
22377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  print 'Tests Passed: %d\n' % passed,
22477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  print 'Tests Failed: %d\n' % failed,
225e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines  if failed:
226e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    print 'Failures:',
227e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines    for t in failed_tests:
228e5e64432476a44b59c61ded233b1149109c7a7c3Stephen Hines      print t,
22977b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23077b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  return failed != 0
23177b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23277b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines
23377b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hinesif __name__ == '__main__':
23477b5baba8349b0741c36f4c0db86660bc0a96991Stephen Hines  sys.exit(main())
235