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