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') 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' 18088bb794545936b6915f4ce22fd4404b3cda3bbd7Stephen Hines ' -v, --verbose Verbose output\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