comparison tests/run-tests.py @ 28284:0fe00bdb2f4f

run-tests: fix Python 3 incompatibilities At one point run-tests.py and test-run-tests.t worked and passed under Python 3.5. Various changes to run-tests.py over the past several months appear to have broken Python 3.5 compatibility. This patch implements various fixes (all related to str/bytes type coercion) to make run-tests.py and test-run-tests.t mostly work again. There are still a few failures in test-run-tests.t due to issues importing mercurial.* modules. But at least run-tests.py seems to work under 3.5 again.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 27 Feb 2016 21:29:42 -0800
parents 2836a43c7722
children 8de70574be2c
comparison
equal deleted inserted replaced
28283:544444991c83 28284:0fe00bdb2f4f
696 killdaemons(entry) 696 killdaemons(entry)
697 self._daemonpids = [] 697 self._daemonpids = []
698 698
699 if self._keeptmpdir: 699 if self._keeptmpdir:
700 log('\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s' % 700 log('\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s' %
701 (self._testtmp, self._threadtmp)) 701 (self._testtmp.decode('utf-8'),
702 self._threadtmp.decode('utf-8')))
702 else: 703 else:
703 shutil.rmtree(self._testtmp, True) 704 shutil.rmtree(self._testtmp, True)
704 shutil.rmtree(self._threadtmp, True) 705 shutil.rmtree(self._threadtmp, True)
705 706
706 if (self._ret != 0 or self._out != self._refout) and not self._skipped \ 707 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
719 def abort(self): 720 def abort(self):
720 """Terminate execution of this test.""" 721 """Terminate execution of this test."""
721 self._aborted = True 722 self._aborted = True
722 723
723 def _portmap(self, i): 724 def _portmap(self, i):
724 offset = '' if i == 0 else '%s' % i 725 offset = b'' if i == 0 else b'%d' % i
725 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset) 726 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
726 727
727 def _getreplacements(self): 728 def _getreplacements(self):
728 """Obtain a mapping of text replacements to apply to test output. 729 """Obtain a mapping of text replacements to apply to test output.
729 730
907 bchr = lambda x: bytes([x]) 908 bchr = lambda x: bytes([x])
908 909
909 class TTest(Test): 910 class TTest(Test):
910 """A "t test" is a test backed by a .t file.""" 911 """A "t test" is a test backed by a .t file."""
911 912
912 SKIPPED_PREFIX = 'skipped: ' 913 SKIPPED_PREFIX = b'skipped: '
913 FAILED_PREFIX = 'hghave check failed: ' 914 FAILED_PREFIX = b'hghave check failed: '
914 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search 915 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
915 916
916 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub 917 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
917 ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256)) 918 ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
918 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'}) 919 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
1211 if el == l: # perfect match (fast) 1212 if el == l: # perfect match (fast)
1212 return True 1213 return True
1213 if el: 1214 if el:
1214 if el.endswith(b" (?)\n"): 1215 if el.endswith(b" (?)\n"):
1215 retry = "retry" 1216 retry = "retry"
1216 el = el[:-5] + "\n" 1217 el = el[:-5] + b"\n"
1217 if el.endswith(b" (esc)\n"): 1218 if el.endswith(b" (esc)\n"):
1218 if PYTHON3: 1219 if PYTHON3:
1219 el = el[:-7].decode('unicode_escape') + '\n' 1220 el = el[:-7].decode('unicode_escape') + '\n'
1220 el = el.encode('utf-8') 1221 el = el.encode('utf-8')
1221 else: 1222 else:
1243 missing = [] 1244 missing = []
1244 failed = [] 1245 failed = []
1245 for line in lines: 1246 for line in lines:
1246 if line.startswith(TTest.SKIPPED_PREFIX): 1247 if line.startswith(TTest.SKIPPED_PREFIX):
1247 line = line.splitlines()[0] 1248 line = line.splitlines()[0]
1248 missing.append(line[len(TTest.SKIPPED_PREFIX):]) 1249 missing.append(line[len(TTest.SKIPPED_PREFIX):].decode('utf-8'))
1249 elif line.startswith(TTest.FAILED_PREFIX): 1250 elif line.startswith(TTest.FAILED_PREFIX):
1250 line = line.splitlines()[0] 1251 line = line.splitlines()[0]
1251 failed.append(line[len(TTest.FAILED_PREFIX):]) 1252 failed.append(line[len(TTest.FAILED_PREFIX):].decode('utf-8'))
1252 1253
1253 return missing, failed 1254 return missing, failed
1254 1255
1255 @staticmethod 1256 @staticmethod
1256 def _escapef(m): 1257 def _escapef(m):
1640 # newest. 1641 # newest.
1641 1642
1642 def loadtimes(testdir): 1643 def loadtimes(testdir):
1643 times = [] 1644 times = []
1644 try: 1645 try:
1645 with open(os.path.join(testdir, '.testtimes-')) as fp: 1646 with open(os.path.join(testdir, b'.testtimes-')) as fp:
1646 for line in fp: 1647 for line in fp:
1647 ts = line.split() 1648 ts = line.split()
1648 times.append((ts[0], [float(t) for t in ts[1:]])) 1649 times.append((ts[0], [float(t) for t in ts[1:]]))
1649 except IOError as err: 1650 except IOError as err:
1650 if err.errno != errno.ENOENT: 1651 if err.errno != errno.ENOENT:
1660 if test not in skipped: 1661 if test not in skipped:
1661 ts = saved.setdefault(test, []) 1662 ts = saved.setdefault(test, [])
1662 ts.append(real) 1663 ts.append(real)
1663 ts[:] = ts[-maxruns:] 1664 ts[:] = ts[-maxruns:]
1664 1665
1665 fd, tmpname = tempfile.mkstemp(prefix='.testtimes', 1666 fd, tmpname = tempfile.mkstemp(prefix=b'.testtimes',
1666 dir=testdir, text=True) 1667 dir=testdir, text=True)
1667 with os.fdopen(fd, 'w') as fp: 1668 with os.fdopen(fd, 'w') as fp:
1668 for name, ts in sorted(saved.iteritems()): 1669 for name, ts in sorted(saved.items()):
1669 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts]))) 1670 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
1670 timepath = os.path.join(testdir, '.testtimes') 1671 timepath = os.path.join(testdir, b'.testtimes')
1671 try: 1672 try:
1672 os.unlink(timepath) 1673 os.unlink(timepath)
1673 except OSError: 1674 except OSError:
1674 pass 1675 pass
1675 try: 1676 try:
1737 t.appendChild(cd) 1738 t.appendChild(cd)
1738 s.appendChild(t) 1739 s.appendChild(t)
1739 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8')) 1740 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
1740 1741
1741 if self._runner.options.json: 1742 if self._runner.options.json:
1742 jsonpath = os.path.join(self._runner._testdir, 'report.json') 1743 jsonpath = os.path.join(self._runner._testdir, b'report.json')
1743 with open(jsonpath, 'w') as fp: 1744 with open(jsonpath, 'w') as fp:
1744 timesd = {} 1745 timesd = {}
1745 for tdata in result.times: 1746 for tdata in result.times:
1746 test = tdata[0] 1747 test = tdata[0]
1747 timesd[test] = tdata[1:] 1748 timesd[test] = tdata[1:]
1752 ('failure', result.failures), 1753 ('failure', result.failures),
1753 ('skip', result.skipped)] 1754 ('skip', result.skipped)]
1754 for res, testcases in groups: 1755 for res, testcases in groups:
1755 for tc, __ in testcases: 1756 for tc, __ in testcases:
1756 if tc.name in timesd: 1757 if tc.name in timesd:
1758 diff = result.faildata.get(tc.name, b'')
1757 tres = {'result': res, 1759 tres = {'result': res,
1758 'time': ('%0.3f' % timesd[tc.name][2]), 1760 'time': ('%0.3f' % timesd[tc.name][2]),
1759 'cuser': ('%0.3f' % timesd[tc.name][0]), 1761 'cuser': ('%0.3f' % timesd[tc.name][0]),
1760 'csys': ('%0.3f' % timesd[tc.name][1]), 1762 'csys': ('%0.3f' % timesd[tc.name][1]),
1761 'start': ('%0.3f' % timesd[tc.name][3]), 1763 'start': ('%0.3f' % timesd[tc.name][3]),
1762 'end': ('%0.3f' % timesd[tc.name][4]), 1764 'end': ('%0.3f' % timesd[tc.name][4]),
1763 'diff': result.faildata.get(tc.name, 1765 'diff': diff.decode('unicode_escape'),
1764 ''),
1765 } 1766 }
1766 else: 1767 else:
1767 # blacklisted test 1768 # blacklisted test
1768 tres = {'result': res} 1769 tres = {'result': res}
1769 1770