"Fossies" - the Fresh Open Source Software Archive

Member "reportlab-3.5.32/src/reportlab/lib/testutils.py" (24 Oct 2019, 11835 Bytes) of package /linux/privat/reportlab-3.5.32.tar.gz:


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. For more information about "testutils.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.5.31_vs_3.5.32.

    1 #Copyright ReportLab Europe Ltd. 2000-2017
    2 #see license.txt for license details
    3 import reportlab
    4 reportlab._rl_testing=True
    5 del reportlab
    6 __version__='3.3.0'
    7 __doc__="""Provides support for the test suite.
    8 
    9 The test suite as a whole, and individual tests, need to share
   10 certain support functions.  We have to put these in here so they
   11 can always be imported, and so that individual tests need to import
   12 nothing more than "reportlab.whatever..."
   13 """
   14 
   15 import sys, os, fnmatch, re
   16 try:
   17     from configparser import ConfigParser
   18 except ImportError:
   19     from ConfigParser import ConfigParser
   20 import unittest
   21 from reportlab.lib.utils import isCompactDistro, __rl_loader__, rl_isdir, asUnicode
   22 from reportlab import ascii
   23 
   24 # Helper functions.
   25 def isWritable(D):
   26     try:
   27         fn = '00DELETE.ME'
   28         f = open(fn, 'w')
   29         f.write('test of writability - can be deleted')
   30         f.close()
   31         if os.path.isfile(fn):
   32             os.remove(fn)
   33             return 1
   34     except:
   35         return 0
   36 
   37 _OUTDIR = None
   38 RL_HOME = None
   39 testsFolder = None
   40 def setOutDir(name):
   41     """Is it a writable file system distro being invoked within
   42     test directory?  If so, can write test output here.  If not,
   43     it had better go in a temp directory.  Only do this once per
   44     process"""
   45     global _OUTDIR, RL_HOME, testsFolder
   46     if _OUTDIR: return _OUTDIR
   47     D = [d[9:] for d in sys.argv if d.startswith('--outdir=')]
   48     if not D:
   49         D = os.environ.get('RL_TEST_OUTDIR','')
   50         if D: D=[D]
   51     if D:
   52         _OUTDIR = D[-1]
   53         try:
   54             os.makedirs(_OUTDIR)
   55         except:
   56             pass
   57         for d in D:
   58             if d in sys.argv:
   59                 sys.argv.remove(d)
   60     else:
   61         assert name=='__main__',"setOutDir should only be called in the main script"
   62         scriptDir=os.path.dirname(sys.argv[0])
   63         if not scriptDir: scriptDir=os.getcwd()
   64         _OUTDIR = scriptDir
   65 
   66     if not isWritable(_OUTDIR):
   67         _OUTDIR = get_rl_tempdir('reportlab_test')
   68 
   69     import reportlab
   70     RL_HOME=reportlab.__path__[0]
   71     if not os.path.isabs(RL_HOME): RL_HOME=os.path.normpath(os.path.abspath(RL_HOME))
   72     topDir = os.path.dirname(RL_HOME)
   73     testsFolder = os.path.join(topDir,'tests')
   74     if not os.path.isdir(testsFolder):
   75         testsFolder = os.path.join(os.path.dirname(topDir),'tests')
   76     if not os.path.isdir(testsFolder):
   77         if name=='__main__':
   78             scriptDir=os.path.dirname(sys.argv[0])
   79             if not scriptDir: scriptDir=os.getcwd()
   80             testsFolder = os.path.abspath(scriptDir)
   81         else:
   82             testsFolder = None
   83     if testsFolder:
   84         sys.path.insert(0,os.path.dirname(testsFolder))
   85     return _OUTDIR
   86 
   87 def outputfile(fn):
   88     """This works out where to write test output.  If running
   89     code in a locked down file system, this will be a
   90     temp directory; otherwise, the output of 'test_foo.py' will
   91     normally be a file called 'test_foo.pdf', next door.
   92     """
   93     D = setOutDir(__name__)
   94     if fn: D = os.path.join(D,fn)
   95     return D
   96 
   97 def printLocation(depth=1):
   98     if sys._getframe(depth).f_locals.get('__name__')=='__main__':
   99         outDir = outputfile('')
  100         if outDir!=_OUTDIR:
  101             print('Logs and output files written to folder "%s"' % outDir)
  102 
  103 def makeSuiteForClasses(*classes):
  104     "Return a test suite with tests loaded from provided classes."
  105 
  106     suite = unittest.TestSuite()
  107     loader = unittest.TestLoader()
  108     for C in classes:
  109         suite.addTest(loader.loadTestsFromTestCase(C))
  110     return suite
  111 
  112 def getCVSEntries(folder, files=1, folders=0):
  113     """Returns a list of filenames as listed in the CVS/Entries file.
  114 
  115     'folder' is the folder that should contain the CVS subfolder.
  116     If there is no such subfolder an empty list is returned.
  117     'files' is a boolean; 1 and 0 means to return files or not.
  118     'folders' is a boolean; 1 and 0 means to return folders or not.
  119     """
  120 
  121     join = os.path.join
  122 
  123     # If CVS subfolder doesn't exist return empty list.
  124     try:
  125         f = open(join(folder, 'CVS', 'Entries'))
  126     except IOError:
  127         return []
  128 
  129     # Return names of files and/or folders in CVS/Entries files.
  130     allEntries = []
  131     for line in f.readlines():
  132         if folders and line[0] == 'D' \
  133            or files and line[0] != 'D':
  134             entry = line.split('/')[1]
  135             if entry:
  136                 allEntries.append(join(folder, entry))
  137 
  138     return allEntries
  139 
  140 
  141 # Still experimental class extending ConfigParser's behaviour.
  142 class ExtConfigParser(ConfigParser):
  143     "A slightly extended version to return lists of strings."
  144 
  145     pat = re.compile(r'\s*\[.*\]\s*')
  146 
  147     def getstringlist(self, section, option):
  148         "Coerce option to a list of strings or return unchanged if that fails."
  149 
  150         value = ConfigParser.get(self, section, option)
  151 
  152         # This seems to allow for newlines inside values
  153         # of the config file, but be careful!!
  154         val = value.replace('\n', '')
  155 
  156         if self.pat.match(val):
  157             return eval(val,{})
  158         else:
  159             return value
  160 
  161 
  162 # This class as suggested by /F with an additional hook
  163 # to be able to filter filenames.
  164 
  165 class GlobDirectoryWalker:
  166     "A forward iterator that traverses files in a directory tree."
  167 
  168     def __init__(self, directory, pattern='*'):
  169         self.index = 0
  170         self.pattern = pattern
  171         directory.replace('/',os.sep)
  172         if os.path.isdir(directory):
  173             self.stack = [directory]
  174             self.files = []
  175         else:
  176             if not isCompactDistro() or not __rl_loader__ or not rl_isdir(directory):
  177                 raise ValueError('"%s" is not a directory' % directory)
  178             self.directory = directory[len(__rl_loader__.archive)+len(os.sep):]
  179             pfx = self.directory+os.sep
  180             n = len(pfx)
  181             self.files = list(map(lambda x, n=n: x[n:],list(filter(lambda x,pfx=pfx: x.startswith(pfx),list(__rl_loader__._files.keys())))))
  182             self.files.sort()
  183             self.stack = []
  184 
  185     def __getitem__(self, index):
  186         while 1:
  187             try:
  188                 file = self.files[self.index]
  189                 self.index = self.index + 1
  190             except IndexError:
  191                 # pop next directory from stack
  192                 self.directory = self.stack.pop()
  193                 self.files = os.listdir(self.directory)
  194                 # now call the hook
  195                 self.files = self.filterFiles(self.directory, self.files)
  196                 self.index = 0
  197             else:
  198                 # got a filename
  199                 fullname = os.path.join(self.directory, file)
  200                 if os.path.isdir(fullname) and not os.path.islink(fullname):
  201                     self.stack.append(fullname)
  202                 if fnmatch.fnmatch(file, self.pattern):
  203                     return fullname
  204 
  205     def filterFiles(self, folder, files):
  206         "Filter hook, overwrite in subclasses as needed."
  207 
  208         return files
  209 
  210 
  211 class RestrictedGlobDirectoryWalker(GlobDirectoryWalker):
  212     "An restricted directory tree iterator."
  213 
  214     def __init__(self, directory, pattern='*', ignore=None):
  215         GlobDirectoryWalker.__init__(self, directory, pattern)
  216 
  217         if ignore == None:
  218             ignore = []
  219         ip = [].append
  220         if isinstance(ignore,(tuple,list)):
  221             for p in ignore:
  222                 ip(p)
  223         elif isinstance(ignore,str):
  224             ip(ignore)
  225         self.ignorePatterns = ([_.replace('/',os.sep) for _ in ip.__self__] if os.sep != '/'
  226                                 else ip.__self__)
  227 
  228     def filterFiles(self, folder, files):
  229         "Filters all items from files matching patterns to ignore."
  230 
  231         fnm = fnmatch.fnmatch
  232         indicesToDelete = []
  233         for i,f in enumerate(files):
  234             for p in self.ignorePatterns:
  235                 if fnm(f, p) or fnm(os.path.join(folder,f),p):
  236                     indicesToDelete.append(i)
  237         indicesToDelete.reverse()
  238         for i in indicesToDelete:
  239             del files[i]
  240 
  241         return files
  242 
  243 
  244 class CVSGlobDirectoryWalker(GlobDirectoryWalker):
  245     "An directory tree iterator that checks for CVS data."
  246 
  247     def filterFiles(self, folder, files):
  248         """Filters files not listed in CVS subfolder.
  249 
  250         This will look in the CVS subfolder of 'folder' for
  251         a file named 'Entries' and filter all elements from
  252         the 'files' list that are not listed in 'Entries'.
  253         """
  254 
  255         join = os.path.join
  256         cvsFiles = getCVSEntries(folder)
  257         if cvsFiles:
  258             indicesToDelete = []
  259             for i in range(len(files)):
  260                 f = files[i]
  261                 if join(folder, f) not in cvsFiles:
  262                     indicesToDelete.append(i)
  263             indicesToDelete.reverse()
  264             for i in indicesToDelete:
  265                 del files[i]
  266 
  267         return files
  268 
  269 
  270 # An experimental untested base class with additional 'security'.
  271 
  272 class SecureTestCase(unittest.TestCase):
  273     """Secure testing base class with additional pre- and postconditions.
  274 
  275     We try to ensure that each test leaves the environment it has
  276     found unchanged after the test is performed, successful or not.
  277 
  278     Currently we restore sys.path and the working directory, but more
  279     of this could be added easily, like removing temporary files or
  280     similar things.
  281 
  282     Use this as a base class replacing unittest.TestCase and call
  283     these methods in subclassed versions before doing your own
  284     business!
  285     """
  286 
  287     def setUp(self):
  288         "Remember sys.path and current working directory."
  289         self._initialPath = sys.path[:]
  290         self._initialWorkDir = os.getcwd()
  291 
  292     def tearDown(self):
  293         "Restore previous sys.path and working directory."
  294         sys.path = self._initialPath
  295         os.chdir(self._initialWorkDir)
  296 
  297 class NearTestCase(unittest.TestCase):
  298     def assertNear(a,b,accuracy=1e-5):
  299         if isinstance(a,(float,int)):
  300             if abs(a-b)>accuracy:
  301                 raise AssertionError("%s not near %s" % (a, b))
  302         else:
  303             for ae,be in zip(a,b):
  304                 if abs(ae-be)>accuracy:
  305                     raise AssertionError("%s not near %s" % (a, b))
  306     assertNear = staticmethod(assertNear)
  307 
  308 class ScriptThatMakesFileTest(unittest.TestCase):
  309     """Runs a Python script at OS level, expecting it to produce a file.
  310 
  311     It CDs to the working directory to run the script."""
  312     def __init__(self, scriptDir, scriptName, outFileName, verbose=0):
  313         self.scriptDir = scriptDir
  314         self.scriptName = scriptName
  315         self.outFileName = outFileName
  316         self.verbose = verbose
  317         # normally, each instance is told which method to run)
  318         unittest.TestCase.__init__(self)
  319 
  320     def setUp(self):
  321         self.cwd = os.getcwd()
  322         global testsFolder
  323         scriptDir=self.scriptDir
  324         if not os.path.isabs(scriptDir):
  325             scriptDir=os.path.join(testsFolder,scriptDir)
  326 
  327         os.chdir(scriptDir)
  328         assert os.path.isfile(self.scriptName), "Script %s not found!" % self.scriptName
  329         if os.path.isfile(self.outFileName):
  330             os.remove(self.outFileName)
  331 
  332     def tearDown(self):
  333         os.chdir(self.cwd)
  334 
  335     def runTest(self):
  336         fmt = sys.platform=='win32' and '"%s" %s' or '%s %s'
  337         import subprocess
  338         out = subprocess.check_output((sys.executable,self.scriptName))
  339         #p = os.popen(fmt % (sys.executable,self.scriptName),'r')
  340         #out = p.read()
  341         if self.verbose:
  342             print(out)
  343         #status = p.close()
  344         assert os.path.isfile(self.outFileName), "File %s not created!" % self.outFileName
  345 
  346 def equalStrings(a,b,enc='utf8'):
  347     return a==b if type(a)==type(b) else asUnicode(a,enc)==asUnicode(b,enc)
  348 
  349 def eqCheck(r,x):
  350     if r!=x:
  351         print('Strings unequal\nexp: %s\ngot: %s' % (ascii(x),ascii(r)))