Back to index

enigmail  1.4.3
runtests.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Run the test(s) listed on the command line. If a directory is listed, the script will recursively
00004 walk the directory for files named .mk and run each.
00005 
00006 For each test, we run gmake -f test.mk. By default, make must exit with an exit code of 0, and must print 'TEST-PASS'.
00007 
00008 Each test is run in an empty directory.
00009 
00010 The test file may contain lines at the beginning to alter the default behavior. These are all evaluated as python:
00011 
00012 #T commandline: ['extra', 'params', 'here']
00013 #T returncode: 2
00014 #T returncode-on: {'win32': 2}
00015 #T environment: {'VAR': 'VALUE}
00016 #T grep-for: "text"
00017 """
00018 
00019 from subprocess import Popen, PIPE, STDOUT
00020 from optparse import OptionParser
00021 import os, re, sys, shutil, glob
00022 
00023 class ParentDict(dict):
00024     def __init__(self, parent, **kwargs):
00025         self.d = dict(kwargs)
00026         self.parent = parent
00027 
00028     def __setitem__(self, k, v):
00029         self.d[k] = v
00030 
00031     def __getitem__(self, k):
00032         if k in self.d:
00033             return self.d[k]
00034 
00035         return self.parent[k]
00036 
00037 thisdir = os.path.dirname(os.path.abspath(__file__))
00038 
00039 pymake = [sys.executable, os.path.join(os.path.dirname(thisdir), 'make.py')]
00040 manifest = os.path.join(thisdir, 'tests.manifest')
00041 
00042 o = OptionParser()
00043 o.add_option('-g', '--gmake',
00044              dest="gmake", default="gmake")
00045 o.add_option('-d', '--tempdir',
00046              dest="tempdir", default="_mktests")
00047 opts, args = o.parse_args()
00048 
00049 if len(args) == 0:
00050     args = [thisdir]
00051 
00052 makefiles = []
00053 for a in args:
00054     if os.path.isfile(a):
00055         makefiles.append(a)
00056     elif os.path.isdir(a):
00057         makefiles.extend(glob.glob(os.path.join(a, '*.mk')))
00058 
00059 def runTest(makefile, make, logfile, options):
00060     """
00061     Given a makefile path, test it with a given `make` and return
00062     (pass, message).
00063     """
00064 
00065     if os.path.exists(opts.tempdir): shutil.rmtree(opts.tempdir)
00066     os.mkdir(opts.tempdir, 0755)
00067 
00068     logfd = open(logfile, 'w')
00069     p = Popen(make + options['commandline'], stdout=logfd, stderr=STDOUT, env=options['env'])
00070     logfd.close()
00071     retcode = p.wait()
00072 
00073     if retcode != options['returncode']:
00074         return False, "FAIL (returncode=%i)" % retcode
00075         
00076     logfd = open(logfile)
00077     stdout = logfd.read()
00078     logfd.close()
00079 
00080     if stdout.find('TEST-FAIL') != -1:
00081         print stdout
00082         return False, "FAIL (TEST-FAIL printed)"
00083 
00084     if options['grepfor'] and stdout.find(options['grepfor']) == -1:
00085         print stdout
00086         return False, "FAIL (%s not in output)" % options['grepfor']
00087 
00088     if options['returncode'] == 0 and stdout.find('TEST-PASS') == -1:
00089         print stdout
00090         return False, 'FAIL (No TEST-PASS printed)'
00091 
00092     if options['returncode'] != 0:
00093         return True, 'PASS (retcode=%s)' % retcode
00094 
00095     return True, 'PASS'
00096 
00097 print "%-30s%-28s%-28s" % ("Test:", "gmake:", "pymake:")
00098 
00099 gmakefails = 0
00100 pymakefails = 0
00101 
00102 tre = re.compile('^#T (gmake |pymake )?([a-z-]+)(?:: (.*))?$')
00103 
00104 for makefile in makefiles:
00105     # For some reason, MAKEFILE_LIST uses native paths in GNU make on Windows
00106     # (even in MSYS!) so we pass both TESTPATH and NATIVE_TESTPATH
00107     cline = ['-C', opts.tempdir, '-f', os.path.abspath(makefile), 'TESTPATH=%s' % thisdir.replace('\\','/'), 'NATIVE_TESTPATH=%s' % thisdir]
00108     if sys.platform == 'win32':
00109         #XXX: hack so we can specialize the separator character on windows.
00110         # we really shouldn't need this, but y'know
00111         cline += ['__WIN32__=1']
00112 
00113     options = {
00114         'returncode': 0,
00115         'grepfor': None,
00116         'env': dict(os.environ),
00117         'commandline': cline,
00118         'pass': True,
00119         'skip': False,
00120         }
00121 
00122     gmakeoptions = ParentDict(options)
00123     pymakeoptions = ParentDict(options)
00124 
00125     dmap = {None: options, 'gmake ': gmakeoptions, 'pymake ': pymakeoptions}
00126 
00127     mdata = open(makefile)
00128     for line in mdata:
00129         line = line.strip()
00130         m = tre.search(line)
00131         if m is None:
00132             break
00133 
00134         make, key, data = m.group(1, 2, 3)
00135         d = dmap[make]
00136         if data is not None:
00137             data = eval(data)
00138         if key == 'commandline':
00139             assert make is None
00140             d['commandline'].extend(data)
00141         elif key == 'returncode':
00142             d['returncode'] = data
00143         elif key == 'returncode-on':
00144             if sys.platform in data:
00145                 d['returncode'] = data[sys.platform]
00146         elif key == 'environment':
00147             for k, v in data.iteritems():
00148                 d['env'][k] = v
00149         elif key == 'grep-for':
00150             d['grepfor'] = data
00151         elif key == 'fail':
00152             d['pass'] = False
00153         elif key == 'skip':
00154             d['skip'] = True
00155         else:
00156             print >>sys.stderr, "%s: Unexpected #T key: %s" % (makefile, key)
00157             sys.exit(1)
00158 
00159     mdata.close()
00160 
00161     if gmakeoptions['skip']:
00162         gmakepass, gmakemsg = True, ''
00163     else:
00164         gmakepass, gmakemsg = runTest(makefile, [opts.gmake],
00165                                       makefile + '.gmakelog', gmakeoptions)
00166 
00167     if gmakeoptions['pass']:
00168         if not gmakepass:
00169             gmakefails += 1
00170     else:
00171         if gmakepass:
00172             gmakefails += 1
00173             gmakemsg = "UNEXPECTED PASS"
00174         else:
00175             gmakemsg = "KNOWN FAIL"
00176 
00177     if pymakeoptions['skip']:
00178         pymakepass, pymakemsg = True, ''
00179     else:
00180         pymakepass, pymakemsg = runTest(makefile, pymake,
00181                                         makefile + '.pymakelog', pymakeoptions)
00182 
00183     if pymakeoptions['pass']:
00184         if not pymakepass:
00185             pymakefails += 1
00186     else:
00187         if pymakepass:
00188             pymakefails += 1
00189             pymakemsg = "UNEXPECTED PASS"
00190         else:
00191             pymakemsg = "OK (known fail)"
00192 
00193     print "%-30.30s%-28.28s%-28.28s" % (os.path.basename(makefile),
00194                                         gmakemsg, pymakemsg)
00195 
00196 print
00197 print "Summary:"
00198 print "%-30s%-28s%-28s" % ("", "gmake:", "pymake:")
00199 
00200 if gmakefails == 0:
00201     gmakemsg = 'PASS'
00202 else:
00203     gmakemsg = 'FAIL (%i failures)' % gmakefails
00204 
00205 if pymakefails == 0:
00206     pymakemsg = 'PASS'
00207 else:
00208     pymakemsg = 'FAIL (%i failures)' % pymakefails
00209 
00210 print "%-30.30s%-28.28s%-28.28s" % ('', gmakemsg, pymakemsg)
00211 
00212 shutil.rmtree(opts.tempdir)
00213 
00214 if gmakefails or pymakefails:
00215     sys.exit(1)