"Fossies" - the Fresh Open Source Software Archive

Member "relax-5.0.0/test_suite/unit_tests/unit_test_runner.py" (6 Dec 2019, 31898 Bytes) of package /linux/privat/relax-5.0.0.src.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "unit_test_runner.py": 4.1.3_vs_5.0.0.

    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 = ['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()