577 adir = os.path.join(TESTDIR, 'annotated') |
577 adir = os.path.join(TESTDIR, 'annotated') |
578 if not os.path.isdir(adir): |
578 if not os.path.isdir(adir): |
579 os.mkdir(adir) |
579 os.mkdir(adir) |
580 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit) |
580 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit) |
581 |
581 |
|
582 class Test(object): |
|
583 """Encapsulates a single, runnable test.""" |
|
584 |
|
585 def __init__(self, path, options): |
|
586 self._path = path |
|
587 self._options = options |
|
588 |
|
589 def run(self, testtmp, replacements, env): |
|
590 return self._run(testtmp, replacements, env) |
|
591 |
|
592 def _run(self, testtmp, replacements, env): |
|
593 raise NotImplemented('Subclasses must implement Test.run()') |
|
594 |
582 def pytest(test, wd, options, replacements, env): |
595 def pytest(test, wd, options, replacements, env): |
583 py3kswitch = options.py3k_warnings and ' -3' or '' |
596 py3kswitch = options.py3k_warnings and ' -3' or '' |
584 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test) |
597 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test) |
585 vlog("# Running", cmd) |
598 vlog("# Running", cmd) |
586 if os.name == 'nt': |
599 if os.name == 'nt': |
587 replacements.append((r'\r\n', '\n')) |
600 replacements.append((r'\r\n', '\n')) |
588 return run(cmd, wd, options, replacements, env) |
601 return run(cmd, wd, options, replacements, env) |
|
602 |
|
603 class PythonTest(Test): |
|
604 """A Python-based test.""" |
|
605 def _run(self, testtmp, replacements, env): |
|
606 return pytest(self._path, testtmp, self._options, replacements, env) |
589 |
607 |
590 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search |
608 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search |
591 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub |
609 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub |
592 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256)) |
610 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256)) |
593 escapemap.update({'\\': '\\\\', '\r': r'\r'}) |
611 escapemap.update({'\\': '\\\\', '\r': r'\r'}) |
841 |
859 |
842 if warnonly == 2: |
860 if warnonly == 2: |
843 exitcode = False # set exitcode to warned |
861 exitcode = False # set exitcode to warned |
844 return exitcode, postout |
862 return exitcode, postout |
845 |
863 |
|
864 class TTest(Test): |
|
865 """A "t test" is a test backed by a .t file.""" |
|
866 |
|
867 def _run(self, testtmp, replacements, env): |
|
868 return tsttest(self._path, testtmp, self._options, replacements, env) |
|
869 |
846 wifexited = getattr(os, "WIFEXITED", lambda x: False) |
870 wifexited = getattr(os, "WIFEXITED", lambda x: False) |
847 def run(cmd, wd, options, replacements, env): |
871 def run(cmd, wd, options, replacements, env): |
848 """Run command in a sub-process, capturing the output (stdout and stderr). |
872 """Run command in a sub-process, capturing the output (stdout and stderr). |
849 Return a tuple (exitcode, output). output is None in debug mode.""" |
873 Return a tuple (exitcode, output). output is None in debug mode.""" |
850 # TODO: Use subprocess.Popen if we're running on Python 2.4 |
874 # TODO: Use subprocess.Popen if we're running on Python 2.4 |
950 else: |
974 else: |
951 return ignore("doesn't match keyword") |
975 return ignore("doesn't match keyword") |
952 |
976 |
953 if not os.path.basename(lctest).startswith("test-"): |
977 if not os.path.basename(lctest).startswith("test-"): |
954 return skip("not a test file") |
978 return skip("not a test file") |
955 for ext, func, out in testtypes: |
979 for ext, cls, out in testtypes: |
956 if lctest.endswith(ext): |
980 if lctest.endswith(ext): |
957 runner = func |
981 runner = cls |
958 ref = os.path.join(TESTDIR, test + out) |
982 ref = os.path.join(TESTDIR, test + out) |
959 break |
983 break |
960 else: |
984 else: |
961 return skip("unknown test type") |
985 return skip("unknown test type") |
962 |
986 |
963 vlog("# Test", test) |
987 vlog("# Test", test) |
964 |
988 |
965 if os.path.exists(err): |
989 if os.path.exists(err): |
966 os.remove(err) # Remove any previous output files |
990 os.remove(err) # Remove any previous output files |
|
991 |
|
992 t = runner(testpath, options) |
967 |
993 |
968 # Make a tmp subdirectory to work in |
994 # Make a tmp subdirectory to work in |
969 threadtmp = os.path.join(HGTMP, "child%d" % count) |
995 threadtmp = os.path.join(HGTMP, "child%d" % count) |
970 testtmp = os.path.join(threadtmp, os.path.basename(test)) |
996 testtmp = os.path.join(threadtmp, os.path.basename(test)) |
971 os.mkdir(threadtmp) |
997 os.mkdir(threadtmp) |
990 env = createenv(options, testtmp, threadtmp, port) |
1016 env = createenv(options, testtmp, threadtmp, port) |
991 createhgrc(env['HGRCPATH'], options) |
1017 createhgrc(env['HGRCPATH'], options) |
992 |
1018 |
993 starttime = time.time() |
1019 starttime = time.time() |
994 try: |
1020 try: |
995 ret, out = runner(testpath, testtmp, options, replacements, env) |
1021 ret, out = t.run(testtmp, replacements, env) |
996 except KeyboardInterrupt: |
1022 except KeyboardInterrupt: |
997 endtime = time.time() |
1023 endtime = time.time() |
998 log('INTERRUPTED: %s (after %d seconds)' % (test, endtime - starttime)) |
1024 log('INTERRUPTED: %s (after %d seconds)' % (test, endtime - starttime)) |
999 raise |
1025 raise |
1000 endtime = time.time() |
1026 endtime = time.time() |
1190 if failed: |
1216 if failed: |
1191 return 1 |
1217 return 1 |
1192 if warned: |
1218 if warned: |
1193 return 80 |
1219 return 80 |
1194 |
1220 |
1195 testtypes = [('.py', pytest, '.out'), |
1221 testtypes = [('.py', PythonTest, '.out'), |
1196 ('.t', tsttest, '')] |
1222 ('.t', TTest, '')] |
1197 |
1223 |
1198 def main(args, parser=None): |
1224 def main(args, parser=None): |
1199 parser = parser or getparser() |
1225 parser = parser or getparser() |
1200 (options, args) = parseargs(args, parser) |
1226 (options, args) = parseargs(args, parser) |
1201 os.umask(022) |
1227 os.umask(022) |