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