1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# #################################################################### 5# Copyright (C) 2005-2019 by the FIFE team 6# http://www.fifengine.net 7# This file is part of FIFE. 8# 9# FIFE is free software; you can redistribute it and/or 10# modify it under the terms of the GNU Lesser General Public 11# License as published by the Free Software Foundation; either 12# version 2.1 of the License, or (at your option) any later version. 13# 14# This library is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17# Lesser General Public License for more details. 18# 19# You should have received a copy of the GNU Lesser General Public 20# License along with this library; if not, write to the 21# Free Software Foundation, Inc., 22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23# #################################################################### 24 25from __future__ import print_function 26from builtins import input 27import os, re, sys, optparse, unittest 28 29def genpath(somepath): 30 return os.path.sep.join(somepath.split('/')) 31 32def print_header(text): 33 print('\n') 34 print(80 * '=') 35 print(text) 36 print(80 * '-') 37 38def resolve_test_progs(sconscript_filename): 39 """ Get the names of all test programs by evaluating the SConscript file """ 40 reprg = re.compile(r"""^env.Program\(["'](.*?)['"]""") 41 progs = [] 42 for line in open(sconscript_filename): 43 m = reprg.match(line.strip()) 44 if m: 45 progs.append(m.group(1)) 46 return progs 47 48def resolve_test_modules(directory): 49 pythonfilenames = [p for p in os.listdir(directory) if len(p) > 3 and p[-3:] == '.py'] 50 modname = directory.replace(os.path.sep, '.') + '.' 51 modules = [] 52 skipped_filenames = ('test_all.py',) 53 for p in pythonfilenames: 54 skip = False 55 for s in skipped_filenames: 56 if p.find(s) != -1: 57 skip = True 58 if p[0] == '_': 59 skip = True 60 if not skip: 61 modules.append(modname + p[:-3]) 62 return modules 63 64def run_core_tests(progs): 65 prevdir = os.getcwd() 66 67 errors, failures = [], [] 68 for prog in progs: 69 print('\n===== Running %s =====' % prog) 70 if os.system(os.sep.join(('build','tests','debug', prog))): 71 errors.append(prog) 72 os.chdir(prevdir) 73 return errors, failures 74 75def get_dynamic_imports(modules): 76 imported = [] 77 for module in modules: 78 m = __import__(module) 79 for part in module.split('.')[1:]: 80 m = getattr(m, part) 81 imported.append(m) 82 return imported 83 84def run_test_modules(modules): 85 imported = get_dynamic_imports(modules) 86 suites = [] 87 for m in imported: 88 try: 89 for c in m.__dict__['TEST_CLASSES']: 90 suites.append(unittest.TestLoader().loadTestsFromTestCase(c)) 91 except (AttributeError, KeyError): 92 pass 93 mastersuite = unittest.TestSuite(suites) 94 runner = unittest.TextTestRunner(verbosity=2) 95 result = runner.run(mastersuite) 96 return [e[1] for e in result.errors], [f[1] for f in result.failures] 97 98def run_all(tests): 99 def print_errors(txt, errs): 100 if errs: 101 print(txt + ':') 102 for msg in errs: 103 print(' ' + msg) 104 105 core_errors, core_failures = run_core_tests(tests['core']) 106 swig_errors, swig_failures = run_test_modules(tests['swig']) 107 ext_errors, ext_failures = run_test_modules(tests['ext']) 108 109 print(80 * '=') 110 errorsfound = False 111 112 if core_errors or core_failures: 113 print_errors('Errors in core tests', core_errors) 114 print_errors('Failures in core tests', core_failures) 115 errorsfound = True 116 else: 117 print('No Core errors found') 118 119 if swig_errors or swig_failures: 120 print_errors('Errors in SWIG tests', swig_errors) 121 print_errors('Failures in SWIG tests', swig_failures) 122 errorsfound = True 123 else: 124 print('No SWIG errors found') 125 126 if swig_errors or swig_failures: 127 print_errors('Errors in extensions tests', ext_errors) 128 print_errors('Failures in extensions tests', ext_failures) 129 errorsfound = True 130 else: 131 print('No Extensions errors found') 132 133 print(80 * '=') 134 if errorsfound: 135 print('ERROR. One or more tests failed!') 136 else: 137 print('OK. All tests ran succesfully!') 138 print('') 139 140def quit(dummy): 141 sys.exit(0) 142 143def run(automatic, selected_cases): 144 index = 0 145 tests = {} 146 147 core_tests = resolve_test_progs(genpath('tests/core_tests/SConscript')) 148 for t in core_tests: 149 tests[index] = ('Core tests', t, [t], run_core_tests) 150 index += 1 151 tests[index] = ('Core tests', 'all', core_tests, run_core_tests) 152 index += 1 153 154 swig_tests = resolve_test_modules(genpath('tests/swig_tests')) 155 for t in swig_tests: 156 tests[index] = ('SWIG tests', t, [t], run_test_modules) 157 index += 1 158 tests[index] = ('SWIG tests', 'all', swig_tests, run_test_modules) 159 index += 1 160 161 extension_tests = resolve_test_modules(genpath('tests/extension_tests')) 162 for t in extension_tests: 163 tests[index] = ('Extension tests', t, [t], run_test_modules) 164 index += 1 165 tests[index] = ('Extension tests', 'all', extension_tests, run_test_modules) 166 index += 1 167 168 alltests = {'core': core_tests, 'swig': swig_tests, 'ext': extension_tests} 169 tests[index] = ('Other', 'Run all tests', alltests, run_all) 170 tests[index+1] = ('Other', 'Cancel and quit', None, quit) 171 172 if (not automatic) and (not selected_cases): 173 selection = None 174 while True: 175 print('Select test module to run:') 176 prevheader = '' 177 for ind in sorted(tests.keys()): 178 header, name, params, fn = tests[ind] 179 if header != prevheader: 180 print(header) 181 prevheader = header 182 print(' %d) %s' % (ind, name)) 183 selection = input('-> : ') 184 185 try: 186 selection = int(selection) 187 if (selection < 0) or (selection > max(tests.keys())): 188 raise ValueError 189 break 190 except ValueError: 191 print('Please enter number between 0-%d\n' % max(tests.keys())) 192 continue 193 header, name, params, fn = tests[selection] 194 fn(params) 195 elif (selected_cases): 196 for case in selected_cases: 197 try: 198 caseid = int(case) 199 if (caseid < 0) or (caseid > max(tests.keys())): 200 raise ValueError 201 header, name, params, fn = tests[caseid] 202 fn(params) 203 except ValueError: 204 print('No test case with value %s found' % case) 205 else: 206 run_all(alltests) 207 208def main(): 209 usage = 'usage: %prog [options] [args]\n' + \ 210 'This is a test runner.\n' + \ 211 'It enables you to test functionalities of fifengine core, extensions and the generated swig interface.\n' + \ 212 'You can give a list of test ids as arguments to the script.\n' + \ 213 'This is useful when running a test over and over again with little changes.\n' + \ 214 'Available test ids can be seen from interactive menu (run script without any parameters).\n' + \ 215 'You can also use "-a" to run all tests from the CLI.' 216 parser = optparse.OptionParser(usage) 217 parser.add_option("-a", "--automatic", 218 action="store_true", dest="automatic", default=False, 219 help="In case selected, runs all the tests automatically") 220 options, args = parser.parse_args() 221 run(options.automatic, args) 222 223 224 225 226if __name__ == '__main__': 227 main() 228