Package test_suite :: Package unit_tests :: Module unit_test_runner
[hide private]
[frames] | no frames]

Source Code for Module test_suite.unit_tests.unit_test_runner

  1  #!/usr/bin/env python 
  2  ################################################################################ 
  3  #                                                                              # 
  4  # Copyright (C) 2006-2007 Gary S Thompson                                      # 
  5  # Copyright (C) 2007-2008,2010-2014,2019 Edward d'Auvergne                     # 
  6  #                                                                              # 
  7  #                                                                              # 
  8  # This file is part of the program relax.                                      # 
  9  #                                                                              # 
 10  # This program is free software: you can redistribute it and/or modify         # 
 11  # it under the terms of the GNU General Public License as published by         # 
 12  # the Free Software Foundation, either version 3 of the License, or            # 
 13  # (at your option) any later version.                                          # 
 14  #                                                                              # 
 15  # This program is distributed in the hope that it will be useful,              # 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of               # 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                # 
 18  # GNU General Public License for more details.                                 # 
 19  #                                                                              # 
 20  # You should have received a copy of the GNU General Public License            # 
 21  # along with relax; if not, write to the Free Software                         # 
 22  #                                                                              # 
 23  ################################################################################ 
 24   
 25  # Module docstring. 
 26  """Utilities for unit test running from the command line or within the relax testing frame work. 
 27   
 28  Unit tests in the relax frame work are stored in a directory structure 
 29  rooted at <relax-root-directory>/test_suite/unit_tests. The directory 
 30  unit tests contains a directory structure that mirrors the relax directory 
 31  structure and which ideally contains one unit test file/module for each 
 32  file/module in the relax framework. The default convention is that the unit 
 33  test module for a relax module called <relax-module> is called 
 34  test_<relax-module> (stored in test_<relax-module>.py). The unit test module 
 35  test_<relax-module> should then contain a class called Test_<relax-module> 
 36  which is a child of TestCase and contains methods whose names start with 
 37  'test' and take no arguments other than self. 
 38   
 39  A concrete example: for class <relax-root-directory>/maths-fns/chi2.py FIXME:***complete*** 
 40   
 41   
 42  The framework can discover sets of unit tests from the file system and add 
 43  them to TestSuites either from the command line or programmatically from 
 44  inside another program. It also has the ability to search for a  root unit 
 45  test and system directory from a position anywhere inside the unit test 
 46  hierarchy. 
 47   
 48  TODO: Examine PEP 338 and runpy.run_module(modulename): Executing Modules as Scripts for a later 
 49  version of relax that is dependant on python 2.5. 
 50  TODO: Split out runner part from search part. 
 51  """ 
 52   
 53  from copy import copy 
 54  import os, re, sys, unittest, traceback 
 55  from optparse import OptionParser 
 56  from textwrap import dedent 
 57   
 58  # relax module imports. 
 59  from test_suite.formatting import format_test_name 
 60  try: 
 61      from test_suite.relax_test_loader import RelaxTestLoader as TestLoader 
 62  except ImportError: 
 63      from unittest import TestLoader 
 64   
 65   
 66  # constants 
 67  ########### 
 68   
 69  PY_FILE_EXTENSION='.py' 
 70   
 71   
 72  # utility functions 
 73  ################### 
 74   
 75   
76 -def get_startup_path():
77 """Get the path of the directory the program started from. 78 79 The startup path is the first path in sys.path (the internal PYTHONPATH) by convention. If the 80 first element of sys.path is an empty trying the current working directory is used instead. 81 82 @return: A file system path for the current operating system. 83 @rtype: str 84 """ 85 86 startup_path = sys.path[0] 87 if startup_path == '': 88 startup_path = os.getcwd() 89 return startup_path
90 91
92 -def import_module(module_path):
93 """Import the python module named by module_path. 94 95 @param module_path: A module path in python dot separated format. Note: this currently doesn't 96 support relative module paths as defined by pep328 and python 2.5. 97 @type module_path: str 98 @return: The module path as a list of module instances or None if the module path 99 cannot be found in the python path. 100 @rtype: list of class module instances or None 101 """ 102 103 module = None 104 result = None 105 106 #try: 107 module = __import__(module_path) 108 #except: 109 # print('failed') 110 # sys.exit() 111 112 if module != None: 113 result = [module] 114 components = module_path.split('.') 115 for component in components[1:]: 116 module = getattr(module, component) 117 result.append(module) 118 return result
119 120
121 -def get_module_relative_path(package_path, module_name, root_paths=None):
122 """Find the relative path of a module to one of a set of root paths using a list of package paths and a module name. 123 124 As the module may match more than one path the first path that can contain it is chosen. 125 126 @param package_path: Path of a python packages leading to module_name. 127 @type package_path: str 128 @param module_name: The name of the module to load. 129 @type module_name: str 130 @keyword root_paths: A set of paths to search for the module in. If None is passed the list 131 is initialized from the internal PYTHONPATH sys.path. Elements which 132 are empty strings are replace with the current working directory 133 sys.getcwd(). 134 @type root_paths: list of str 135 @return: A relative module path to one of the rootPaths which is separated by 136 '.'s if the modulePath is a subpath of one of the root paths, otherwise 137 None. 138 @rtype: str or None 139 """ 140 141 relative_path = None 142 if root_paths == None: 143 root_paths = sys.path 144 for root_path in root_paths: 145 root_path = segment_path(os.path.abspath(root_path)) 146 147 # Catch if the package path has already been converted to a segment list. 148 if not isinstance(package_path, list): 149 package_path = segment_path(os.path.abspath(package_path)) 150 151 common_prefix = get_common_prefix(root_path, package_path) 152 if common_prefix == root_path: 153 relative_path = package_path[len(common_prefix):] 154 break 155 156 if relative_path != None: 157 relative_path = '.'.join(relative_path) 158 159 if relative_path != '': 160 relative_path = '.'.join((relative_path, module_name)) 161 else: 162 relative_path = module_name 163 164 165 166 return relative_path
167 168
169 -def get_common_prefix(path1, path2):
170 """Get the common prefix between two paths. 171 172 @param path1: The first path to be compared. 173 @type path1: list of str 174 @param path2: The second path to be compared. 175 @type path2: list of str 176 @return: The common path shared between the two paths starting from the root directory as 177 a list of segments. If there is no common path an empty list is returned. 178 @rtype: list of str 179 """ 180 181 result_path = [] 182 size = min(len(path1), len(path2)) 183 for i in range(size): 184 if path1[i] == None or path2[i] == None: 185 break 186 187 if path1[i] == path2[i]: 188 result_path.append(path1[i]) 189 return result_path
190 191
192 -def segment_path(path, normalise=True):
193 """Segment a path into a list of components (drives, files, directories etc). 194 195 @param path: The path to segment. 196 @type path: str 197 @param normalise: Whether to normalise the path before starting. 198 @type normalise: bool 199 @return: A list of path segments. 200 @rtype: list of str 201 """ 202 203 if normalise: 204 path = os.path.normpath(path) 205 206 result = [] 207 (head, tail) = os.path.split(path) 208 if head =='' or tail == '': 209 result.append(head+tail) 210 else: 211 while head != '' and tail != '': 212 result.append(tail) 213 head, tail = os.path.split(head) 214 result.append(head+tail) 215 result.reverse() 216 return result
217 218
219 -def join_path_segments(segments):
220 """Join a list of path segments (drives, files, directories etc) into a path. 221 222 @param segments: The path segments to join into a path. 223 @type segments: a list of path segments 224 @return: The path containing the joined path segments. 225 @rtype: str 226 """ 227 228 if len(segments) == 0: 229 result = '' 230 else: 231 segments_copy = segments[:] 232 233 segments_copy.reverse() 234 235 result = segments_copy.pop() 236 while len(segments_copy) > 0: 237 result = os.path.join(result, segments_copy.pop()) 238 239 return result
240 241 242
243 -class ImportErrorTestCase(unittest.TestCase):
244 """TestCase class for nicely handling import errors.""" 245
246 - def __init__(self, module_name, message):
247 """Set up the import error class. 248 249 @param module_name: The module which could not be imported. 250 @type module_name: str 251 @param message: The formatted traceback message (e.g. from traceback.format_exc()). 252 @type message: str 253 """ 254 255 # Execute the base class __init__() method. 256 super(ImportErrorTestCase, self).__init__('testImportError') 257 258 # Store the info for printing out at the end of the unit tests. 259 self.module_name = module_name 260 self.message = message
261 262
263 - def testImportError(self):
264 """Unit test module import.""" 265 266 # First print out the module to allow it to be identified and debugged. 267 print("\nImport of the %s module.\n" % self.module_name) 268 269 # Fail! 270 self.fail(self.message)
271 272
273 -def load_test_case(package_path, module_name, class_name):
274 """Load a testCase from the file system using a package path, file name and class name. 275 276 @param package_path: Full system path of the module file. 277 @type package_path: str 278 @param module_name: Name of the module to load the class from. 279 @type module_name: str 280 @param class_name: Name of the class to load. 281 @type class_name: str 282 @return: The suite of test cases. 283 @rtype: TestSuite instance 284 """ 285 286 # Determine the full name of the module. 287 module = get_module_relative_path(package_path, module_name) 288 289 # Catch import errors, adding the ImportErrorTestCase class to the test suite. 290 try: 291 packages = import_module(module) 292 except: 293 # Initialise a test suite. 294 suite = unittest.TestSuite() 295 296 # Add the ImportErrorTestCase. 297 suite.addTest(ImportErrorTestCase(module, traceback.format_exc())) 298 299 # Return the suite. 300 return suite 301 302 # Nothing to do. 303 if not packages: 304 return 305 306 # Some input packages may not contain the required class. 307 if not hasattr(packages[-1], class_name): 308 return 309 310 # Get the class object. 311 clazz = getattr(packages[-1], class_name) 312 313 # Load the test cases and return the suite of test cases. 314 return TestLoader().loadTestsFromTestCase(clazz)
315 316 317
318 -class Test_finder:
319 """Find and load unit test classes as a hierarchy of TestSuites and TestCases. 320 321 The class provides functions for running or returning the resulting TestSuite and requires a 322 root directory to start searching from. 323 324 TestCases are identified by the class name matching a pattern (pattern_string). 325 """ 326 327 suite = unittest.TestSuite() 328 """The root test suite to which testSuites and cases are added.""" 329
330 - def __init__(self, root_path=None, pattern_list=[]):
331 """Initialise the unit test finder. 332 333 @keyword root_path: The path to starts searching for unit tests from, all sub 334 directories and files are searched. 335 @type root_path: str 336 @keyword pattern_list: A list of regular expression patterns which identify a file as one 337 containing a unit test TestCase. 338 @type pattern_list: list of str 339 """ 340 341 self.root_path = root_path 342 if self.root_path == None: 343 self.root_path = get_startup_path() 344 self.patterns=[] 345 for pattern in pattern_list: 346 self.patterns.append(re.compile(pattern)) 347 self.paths_scanned = False
348 349
350 - def scan_paths(self):
351 """Scan directories and paths for unit test classes and load them into TestSuites.""" 352 353 # Initialise the TestSuite object. 354 self.suite = unittest.TestSuite() 355 356 # Loop over all directories recursively. 357 for dir_path, dir_names, file_names in os.walk(self.root_path): 358 # Loop over the files. 359 for file_name in file_names: 360 # Is the file part of the test. 361 module_found = False 362 for pattern in self.patterns: 363 if pattern.match(file_name): 364 module_found = True 365 break 366 367 # If not, skip the file. 368 if not module_found: 369 continue 370 371 # Build the class name from the file name. 372 module_name = os.path.splitext(file_name)[0] 373 class_name = module_name[0].upper() + module_name[1:] 374 375 # Load the test case into the test suite. 376 test_case = load_test_case(dir_path, module_name, class_name) 377 if test_case != None: 378 self.suite.addTest(test_case) 379 else: 380 print("RelaxError: Cannot find the '%s' TestCase class in the '%s' file! Make sure it is correctly named." % (class_name, os.path.join(dir_path, file_name)))
381 382 383
384 -class Unit_test_runner(object):
385 """Class to run a particular unit test or a directory of unit tests.""" 386 387 #constants 388 system_path_pattern = ['test_suite' + os.sep + 'unit_tests', os.pardir + os.sep + os.pardir] 389 """@ivar: A search template for the directory in which relax is installed. The directory which relax is installed in is viewed as the the 'PYTHONPATH' of the classes to be tested. It must be unique and defined relative to the test suite. For the current setup in relax this is (\'test_suite\', /'..\'). The first string is a directory structure to match the second string is a relative path from that directory to the system directory. The search is started from the value of root_path in the file system. 390 @type: list of str 391 """ 392 393 unit_test_path_pattern = ['test_suite' + os.sep + 'unit_tests', os.curdir] 394 """@ivar: A search template for the directory from which all unit module directories descend. For the current setup in relax this is (\'unit_tests\', \'.\'). The search is started from the value of root_path in the file system. 395 @type: list of str 396 """ 397 398 test_case_patterns = [r'test_.*\.py$'] 399 """@ivar: A list of regex patterns against which files will be 400 tested to see if they are expected to contain unit tests. If 401 the file has the correct pattern the module contained inside the 402 file will be searched for testCases e.g in the case of test_float.py 403 the module to be searched for would be test_float.Test_float. 404 @type: list of str 405 """ 406
407 - def __init__(self, root_path=os.curdir, test_module=None, search_for_root_path=True, search_for_unit_test_path=True, verbose=False):
408 """Initialise the unit test runner. 409 410 @keyword root_path: Root path to start searching for modules to unit test from. If the string contains '.' the search starts from the current working directory. Default current working directory. 411 @type root_path: str 412 @keyword test_module: The name of a module to unit test. If the variable is None a search for all unit tests using <test-pattern> will start from <root_path>, if the variable is '.' a search for all unit tests will commence from the current working directory, otherwise it will be used as a module path from the current root_path or CHECKME: ****module_directory_path****. The module name can be in the directory path format used by the current operating system or a unix style path with /'s including a final .py extension or a dotted moudle name. 413 @type test_module: str 414 @keyword search_for_root_path: Whether to carry out a search from the root_directory using self.system_path_pattern to find the directory self.system_directory if no search is carried out self.system_directory is set to None and it is the responsibility of code creating the class to set it before self.run is called. 415 @type search_for_root_path: bool 416 @keyword search_for_unit_test_path: Whether to carry out a search from the root_directory using self.unit_test_path_patter to find the directory self.unit_test_directory if no search is carried out self.unit_test_directory is set to None and it is the responsibility of code creating the class to set it before self.run is called. 417 @type search_for_unit_test_path: bool 418 @keyword verbose: Produce verbose output during testing e.g. directories searched root directories etc. 419 @type verbose: bool 420 """ 421 422 # The root path is the current working directory (translate to the full path). 423 if root_path == os.curdir: 424 root_path = os.getcwd() 425 426 # Store the root path. 427 self.root_path = root_path 428 429 # Verbose printout. 430 if ((search_for_root_path) == True or (search_for_unit_test_path == True)) and verbose: 431 print('\nSearching for paths') 432 print('-------------------') 433 434 # Find system directories or leave it for someone else as needed. 435 if search_for_root_path: 436 self.system_directory = self.get_first_instance_path(root_path, self.system_path_pattern[0], self.system_path_pattern[1]) 437 438 if self.system_directory == None: 439 raise Exception("Can't find system directory start from %s" % root_path) 440 else: 441 if verbose: 442 print('Search for system directory found: %s' % self.system_directory) 443 else: 444 self.system_directory = None 445 446 if search_for_unit_test_path: 447 self.unit_test_directory = self.get_first_instance_path(root_path, self.unit_test_path_pattern[0], self.unit_test_path_pattern[1]) 448 if self.unit_test_directory == None: 449 raise Exception("Can't find unit test directory start from %s" % root_path) 450 else: 451 if verbose: 452 print('Search for unit test directory found: %s' % self.unit_test_directory) 453 else: 454 self.unit_test_directory = None 455 456 # Deal with test_module. 457 if test_module == None: 458 test_module = self.root_path 459 elif test_module == os.curdir: 460 test_module = os.getcwd() 461 462 self.test_module = test_module 463 464 # Other instance variables. 465 self.verbose = verbose
466 467
468 - def get_first_instance_path(self, path, target_path, offset_path=os.curdir):
469 """Get the minimal path searching up the file system to target_directory. 470 471 The algorithm is that we repeatedly chop the end off path and see if the tail of the path matches target_path If it doesn't match we search in the resulting directory by appending target_path and seeing if it exists in the file system. Finally once the required directory structure has been found the offset_path is appended to the found path and the resulting path normalised. 472 473 Note the algorithm understands .. and . 474 475 476 @param path: A directory path to search up. 477 @type path: str 478 @param target_path: A directory to find in the path or below one of the elements in the path. 479 @type target_path: str 480 @keyword offset_path: A relative path offset to add to the path that has been found to give the result directory. 481 @type offset_path: str 482 @return: The path that has been found or None if the path cannot be found by walking up and analysing the current directory structure. 483 @rtype: str 484 """ 485 486 seg_path = segment_path(os.path.normpath(path)) 487 seg_target_directory = segment_path(target_path) 488 seg_target_directory_len = len(seg_target_directory) 489 490 found_seg_path = None 491 while len(seg_path) > 0 and found_seg_path == None: 492 if seg_path[-seg_target_directory_len:] == seg_target_directory[-seg_target_directory_len:]: 493 found_seg_path = seg_path 494 break 495 else: 496 extended_seg_path = copy(seg_path) 497 extended_seg_path.extend(seg_target_directory) 498 if os.path.exists(os.path.join(*extended_seg_path)): 499 found_seg_path = extended_seg_path 500 break 501 502 seg_path.pop() 503 504 result = None 505 if found_seg_path != None and len(found_seg_path) != 0: 506 seg_offset_path = segment_path(offset_path) 507 found_seg_path.extend(seg_offset_path) 508 result = os.path.normpath(join_path_segments(found_seg_path)) 509 510 return result
511 512
513 - def paths_from_test_module(self, test_module):
514 """Determine the possible paths of the test_module. 515 516 It is assumed that the test_module can be either a path or a python module or package name including dots. 517 518 The following heuristics are used: 519 520 1. If the test_module=None add the value '.'. 521 2. If the test_module ends with a PY_FILE_EXTENSION append test_module with the PY_FILE_EXTENSION removed. 522 3. Add the module_name with .'s converted to /'s and any elements of the form PY_FILE_EXTENSION removed. 523 4. Repeat 2 and 3 with the last element of the path repeated with the first letter capitalised. 524 525 Note: we can't deal with module methods... 526 527 528 @return: A set of possible module names in python '.' separated format. 529 @rtype: str 530 """ 531 532 result = [] 533 534 # check for current working directory 535 if test_module == None: 536 result.append(os.curdir) 537 else: 538 # add a direct file 539 mpath = [] 540 test_module_segments = segment_path(test_module) 541 for elem in test_module_segments: 542 if elem.endswith(PY_FILE_EXTENSION): 543 mpath.append(os.path.splitext(elem)[0]) 544 else: 545 mpath.append(elem) 546 547 result.append(tuple(mpath)) 548 549 mpath = copy(mpath) 550 mpath.append(mpath[-1].capitalize()) 551 result.append(tuple(mpath)) 552 553 module_path_elems = test_module.split('.') 554 555 module_norm_path = [] 556 for elem in module_path_elems: 557 if elem != PY_FILE_EXTENSION[1:]: 558 module_norm_path.append(elem) 559 560 # See if we can find a dot separated module. 561 # a package name first 562 elems_ok = True 563 for elem in module_norm_path: 564 if len(segment_path(elem)) > 1: 565 elems_ok = False 566 break 567 568 if elems_ok: 569 result.append(tuple(module_norm_path)) 570 571 mpath = copy(module_norm_path) 572 mpath.append(module_norm_path[-1].capitalize()) 573 result.append(tuple(mpath)) 574 575 return result
576 577
578 - def run(self, tests=None, runner=None, list_tests=False):
579 """Run a unit test or set of unit tests. 580 581 @keyword tests: The list of system tests to perform. 582 @type tests: list of str 583 @keyword runner: A unit test runner such as TextTestRunner. None indicates use of the default unit test runner. For an example of how to write a test runner see the python documentation for TextTestRunner in the python source. 584 @type runner: Unit test runner instance (TextTestRunner, BaseGUITestRunner subclass, etc.) 585 @keyword list_tests: A flag which if True will cause the tests to be listed rather than executed. 586 @type list_tests: bool 587 @return: A string indicating success or failure of the unit tests run. 588 @rtype: str 589 """ 590 591 msg = "Either set self.%s to a %s directory or set search_for_%s_path in self.__init__ to True" 592 if self.unit_test_directory == None: 593 raise Exception(msg % ('unit_test_directory', 'unit test', 'unit_test')) 594 if self.system_directory == None: 595 raise Exception(msg % ('system_directory', 'system', 'root')) 596 597 # Title printout. 598 if self.verbose: 599 print('\nTesting units...') 600 print('----------------') 601 print('') 602 603 # The test module path for individual tests. 604 if tests: 605 # Initialise the list of paths. 606 module_paths = [] 607 608 # Loop over each test. 609 for test in tests: 610 # Strip out the leading 'test_suite.unit_tests.' if present. 611 test = test.replace('test_suite.unit_tests.', '') 612 test = test.replace('test_suite%sunit_tests%s' % (os.sep, os.sep), '') 613 614 # Replace the Python '.' separator with the system's path separator. 615 test = test.replace('.', os.sep) 616 617 # Append to the module path list. 618 module_paths += self.paths_from_test_module(self.test_module+os.sep+test) 619 620 # The test module path for all tests. 621 else: 622 module_paths = self.paths_from_test_module(self.test_module) 623 624 if self.verbose: 625 print("%-22s %s" % ('Test module:', self.test_module)) 626 print("%-22s %s" % ('Root path', self.root_path)) 627 print("%-22s %s" % ('System directory:', self.system_directory)) 628 print("%-22s %s" % ('Unit test directory:', self.unit_test_directory)) 629 for i, elem in enumerate(module_paths): 630 print("%-22s %s" % ('Module path %d:' % i, elem)) 631 print('') 632 633 # add SystemDirectory to python path 634 sys.path.pop(0) 635 sys.path.insert(0, self.system_directory) 636 637 tests = None 638 639 # Load all tests from a directory. 640 for module_path in module_paths: 641 module_string = os.path.join(*module_path) 642 643 if os.path.isdir(module_string): 644 #iterate and load unit tests from module path 645 finder = Test_finder(module_string, self.test_case_patterns) 646 finder.scan_paths() 647 tests = finder.suite 648 break 649 650 # Execute specific tests. 651 if tests == None: 652 for module_tuple in module_paths: 653 # The package path. 654 package_path = module_tuple[0] 655 for i in range(len(module_tuple)-2): 656 package_path = os.path.join(package_path, module_tuple[i]) 657 658 # The module name. 659 module_name = module_tuple[-2] 660 661 # The class name. 662 class_name = module_tuple[-1] 663 664 # Load the tests. 665 tests = load_test_case(package_path, module_name, class_name) 666 667 # Only list the tests. 668 if list_tests: 669 for suite in tests: 670 for test in suite: 671 print(format_test_name(test.id())) 672 return True 673 674 if runner == None: 675 runner = unittest.TextTestRunner() 676 677 if self.verbose: 678 print('Results') 679 print('-------') 680 print('') 681 682 # Run the unit tests and catch the TestResult object. 683 if tests != None and tests.countTestCases() != 0: 684 # Run the test. 685 results = runner.run(tests) 686 result_string = results.wasSuccessful() 687 688 elif tests == None: 689 results = None 690 result_string = 'Error: no test directories found for input module: %s' % self.test_module 691 print(result_string) 692 else: 693 results = None 694 result_string = 'Note: no tests found for input module: %s' % self.test_module 695 print(result_string) 696 697 # Return the result of all the tests. 698 return result_string
699 700 701 702 # Command line usage. 703 if __name__ == '__main__': 704 # Set up the parser options. 705 parser = OptionParser() 706 parser.add_option("-v", "--verbose", dest="verbose", help="verbose test ouput", default=True, action='store_true') 707 parser.add_option("-u", "--system", dest="system_directory", help="path to relax top directory which contains test_suite", default=None) 708 parser.add_option("-s", "--utest", dest="unit_test_directory", help="default unit test directory", default=None) 709 710 # Set the help string. 711 usage = """ 712 %%prog [options] [<file-or-dir>...] 713 714 a program to find and run subsets of the relax unit test suite using pyunit. 715 (details of how to write pyunit tests can be found in your python distributions 716 library reference) 717 718 719 arguments: 720 <file-or-dir> = <file-path> | <dir-path> is a list which can contain 721 inter-mixed directories and files 722 723 <file-path> = a file containing a test case class files of the same 724 name with the first letter capitalised 725 726 e.g. target_functions/test_chi2.py will be assumed to contain 727 a test case class called Test_chi2 728 729 <dir-path> = a path which will be recursivley searched for <file-path>s 730 which end in "*.py". 731 """ 732 parser.set_usage(dedent(usage)) 733 734 # Parse the args. 735 (options, args) = parser.parse_args() 736 737 # Initialise some flags. 738 search_system = True 739 search_unit = True 740 741 # The system directory. 742 if options.system_directory != None: 743 if not os.path.exists(options.system_directory): 744 print("The path to the system directory doeesn't exist") 745 print("provided path: %s" % options.system_directory) 746 print("exiting...") 747 sys.exit(0) 748 search_system = False 749 750 # A unit test directory. 751 if options.unit_test_directory != None: 752 if not os.path.exists(options.unit_test_directory): 753 print("The path to the system directory doeesn't exist") 754 print("provided path: %s" % options.unit_test_directory) 755 print("exiting...") 756 sys.exit(0) 757 search_unit = False 758 759 # No arguments. 760 if len(args) < 1: 761 args = [None] 762 763 # Loop over the arguments. 764 for arg in args: 765 # Initialise the unit test runner. 766 runner = Unit_test_runner(test_module=arg, verbose=options.verbose, search_for_unit_test_path=search_unit, search_for_root_path=search_system) 767 768 # Add the system directory to the runner. 769 if not search_system: 770 runner.system_directory = options.system_directory 771 772 # Add the unit test directory to the runner. 773 if not search_unit: 774 runner.unit_test_directory = options.unit_test_directory 775 776 # Execute the tests. 777 runner.run() 778